|
2743
|
112
|
43
|
2026-05-07T11:38:07.941095+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-07/1778 /Users/lukas/.screenpipe/data/data/2026-05-07/1778153887941_m2.jpg...
|
PhpStorm
|
faVsco.js – laravel.log
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
[2026-05-07 11:36:44] local.INFO: Jiminny\Console\Commands\Command::run Memory usage before starting command {"command":"crm:sync-opportunity","memoryBeforeCommandInMb":60.0,"memoryPeakBeforeCommandInMb":99.727} {"correlation_id":"462baf35-d312-4641-9896-e8b15e8fdb82","trace_id":"aeb070fe-166a-48bf-99c0-acfcbfb40c1b"}
[2026-05-07 11:36:44] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"462baf35-d312-4641-9896-e8b15e8fdb82","trace_id":"aeb070fe-166a-48bf-99c0-acfcbfb40c1b"}
[2026-05-07 11:36:44] local.INFO: [SocialAccountService] Token retrieved {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"462baf35-d312-4641-9896-e8b15e8fdb82","trace_id":"aeb070fe-166a-48bf-99c0-acfcbfb40c1b"}
[2026-05-07 11:36:44] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"462baf35-d312-4641-9896-e8b15e8fdb82","trace_id":"aeb070fe-166a-48bf-99c0-acfcbfb40c1b"}
[2026-05-07 11:36:44] local.INFO: [HubSpot] Syncing opportunities using strategy: lastModified {"team":2} {"correlation_id":"462baf35-d312-4641-9896-e8b15e8fdb82","trace_id":"aeb070fe-166a-48bf-99c0-acfcbfb40c1b"}
[2026-05-07 11:36:45] local.INFO: [Hubspot] Pagination completed {"team_id":2,"endpoint":"[URL_WITH_CREDENTIALS] CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall
* @return T
*
* @throws RateLimitException
*/
private function executeRequest(callable $apiCall)
{
if (! $this->rateLimiter->canMakeRequest($this->config)) {
$retryAfter = $this->rateLimiter->requestAvailableIn($this->config);
$this->log->warning('[Hubspot] Rate limit exceeded, deferring request', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
]);
throw new RateLimitException(
'Hubspot rate limit reached for configuration ' . $this->config->getId(),
$retryAfter,
);
}
$this->rateLimiter->incrementRequestCount($this->config);
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
private function isHubspotRateLimit(Throwable $e): bool
{
return method_exists($e, 'getCode') && (int) $e->getCode() === 429;
}
private function parseRetryAfter(Throwable $e): int
{
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
return 10;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
$deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
));
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
$response = $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
$response = $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
$max = $response->getHeaderLine('X-HubSpot-RateLimit-Max'); // "110"
$remaining = $response->getHeaderLine('X-HubSpot-RateLimit-Remaining'); // "109"
$interval = $response->getHeaderLine('X-HubSpot-RateLimit-Interval-Milliseconds'); // "10000"
$body = json_decode((string) $response->getBody(), true);
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$max ' . PHP_EOL . print_r($max, true));
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$remaining ' . PHP_EOL . print_r($remaining, true));
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$interval ' . PHP_EOL . print_r($interval, true));
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$body ' . PHP_EOL . print_r($body, true));
return $response;
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.034242023,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: master","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8081782,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"bounds":{"left":0.8234708,"top":0.019952115,"width":0.09208777,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"[2026-05-07 11:36:44] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"crm:sync-opportunity\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"462baf35-d312-4641-9896-e8b15e8fdb82\",\"trace_id\":\"aeb070fe-166a-48bf-99c0-acfcbfb40c1b\"}\n[2026-05-07 11:36:44] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"462baf35-d312-4641-9896-e8b15e8fdb82\",\"trace_id\":\"aeb070fe-166a-48bf-99c0-acfcbfb40c1b\"}\n[2026-05-07 11:36:44] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"462baf35-d312-4641-9896-e8b15e8fdb82\",\"trace_id\":\"aeb070fe-166a-48bf-99c0-acfcbfb40c1b\"}\n[2026-05-07 11:36:44] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"462baf35-d312-4641-9896-e8b15e8fdb82\",\"trace_id\":\"aeb070fe-166a-48bf-99c0-acfcbfb40c1b\"}\n[2026-05-07 11:36:44] local.INFO: [HubSpot] Syncing opportunities using strategy: lastModified {\"team\":2} {\"correlation_id\":\"462baf35-d312-4641-9896-e8b15e8fdb82\",\"trace_id\":\"aeb070fe-166a-48bf-99c0-acfcbfb40c1b\"}\n[2026-05-07 11:36:45] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/deals/search\",\"total_requests\":1,\"total_records_fetched\":6,\"total_elapsed_seconds\":0.48,\"average_seconds_per_request\":0.48} {\"correlation_id\":\"462baf35-d312-4641-9896-e8b15e8fdb82\",\"trace_id\":\"aeb070fe-166a-48bf-99c0-acfcbfb40c1b\"}\n[2026-05-07 11:36:46] local.INFO: [HubSpot] importOpportunityBatch timing {\"teamId\":2,\"deal_count\":6,\"total_ms\":659,\"company_assoc_api_ms\":276,\"contact_assoc_api_ms\":203,\"prepare_entities_ms\":19,\"prepare_accounts_ms\":3,\"prepare_contacts_ms\":17,\"total_companies\":5,\"missing_companies\":0,\"total_contacts\":23,\"missing_contacts\":0,\"deals_loop_ms\":152,\"avg_deal_ms\":25,\"slow_deals_count\":0,\"slow_deals\":[]} {\"correlation_id\":\"462baf35-d312-4641-9896-e8b15e8fdb82\",\"trace_id\":\"aeb070fe-166a-48bf-99c0-acfcbfb40c1b\"}\n[2026-05-07 11:36:46] local.INFO: [HubSpot] Synced opportunities {\"team\":2,\"strategies\":\"lastModified\",\"sync_count\":5,\"total\":6,\"last_synced_id\":\"297846423\",\"duration_ms\":1161.39} {\"correlation_id\":\"462baf35-d312-4641-9896-e8b15e8fdb82\",\"trace_id\":\"aeb070fe-166a-48bf-99c0-acfcbfb40c1b\"}\n[2026-05-07 11:36:46] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"crm:sync-opportunity\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"462baf35-d312-4641-9896-e8b15e8fdb82\",\"trace_id\":\"aeb070fe-166a-48bf-99c0-acfcbfb40c1b\"}\n[2026-05-07 11:36:52] local.INFO: [HubSpot Journal Polling] Getting offset from database {\"offset\":\"\",\"jiminny_team_id\":1} {\"correlation_id\":\"8568abe7-be33-417c-aa2f-b1bd53fb4adc\",\"trace_id\":\"582bff07-5ea4-4469-8ca8-efa41b04d46d\"}\n[2026-05-07 11:36:52] local.INFO: [HubSpot Journal API] Fetching latest journal entry {\"url\":\"https://api.hubapi.com/webhooks/v4/journal/latest\"} {\"correlation_id\":\"8568abe7-be33-417c-aa2f-b1bd53fb4adc\",\"trace_id\":\"582bff07-5ea4-4469-8ca8-efa41b04d46d\"}\n[2026-05-07 11:36:52] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"8568abe7-be33-417c-aa2f-b1bd53fb4adc\",\"trace_id\":\"582bff07-5ea4-4469-8ca8-efa41b04d46d\"}\n[2026-05-07 11:36:52] local.WARNING: [HubSpot Journal Polling] Maximum empty results reached, stopping {\"empty_results\":5,\"max_empty_results\":5} {\"correlation_id\":\"8568abe7-be33-417c-aa2f-b1bd53fb4adc\",\"trace_id\":\"582bff07-5ea4-4469-8ca8-efa41b04d46d\"}\n[2026-05-07 11:36:52] local.WARNING: [HubSpot Journal Polling] Maximum empty results reached, stopping {\"empty_results\":5,\"max_empty_results\":5} {\"correlation_id\":\"8568abe7-be33-417c-aa2f-b1bd53fb4adc\",\"trace_id\":\"582bff07-5ea4-4469-8ca8-efa41b04d46d\"}\n[2026-05-07 11:36:52] local.INFO: [HubSpot Journal Polling] Service ending {\"runtime_seconds\":56,\"total_cycles\":5,\"files_downloaded\":0,\"empty_files\":0,\"other_portal_skipped\":0,\"total_events\":0,\"events_per_file\":0,\"avg_api_ms\":176.5,\"avg_download_ms\":0.0,\"avg_transform_ms\":0.0,\"avg_process_ms\":0.0,\"peak_memory_mb\":99.73} {\"correlation_id\":\"8568abe7-be33-417c-aa2f-b1bd53fb4adc\",\"trace_id\":\"582bff07-5ea4-4469-8ca8-efa41b04d46d\"}\n[2026-05-07 11:36:52] local.INFO: [HubSpot Journal Polling] Released polling lock {\"correlation_id\":\"8568abe7-be33-417c-aa2f-b1bd53fb4adc\",\"trace_id\":\"582bff07-5ea4-4469-8ca8-efa41b04d46d\"}\n[2026-05-07 11:37:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"34ae70b9-ee92-4e0c-bb97-3ecc204278be\",\"trace_id\":\"0d02e69d-5e33-4059-938c-d41350a39b72\"}\n[2026-05-07 11:37:05] local.INFO: [ScheduleBotCommand] Number of activities to be captured: 0 {\"correlation_id\":\"34ae70b9-ee92-4e0c-bb97-3ecc204278be\",\"trace_id\":\"0d02e69d-5e33-4059-938c-d41350a39b72\"}\n[2026-05-07 11:37:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"34ae70b9-ee92-4e0c-bb97-3ecc204278be\",\"trace_id\":\"0d02e69d-5e33-4059-938c-d41350a39b72\"}\n[2026-05-07 11:37:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":62.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"6052f7ad-dde1-41de-8051-5ba8d54babdd\",\"trace_id\":\"2e216848-ddf9-4f8c-8808-93a09cef8f5f\"}\n[2026-05-07 11:37:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":62.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"6052f7ad-dde1-41de-8051-5ba8d54babdd\",\"trace_id\":\"2e216848-ddf9-4f8c-8808-93a09cef8f5f\"}\n[2026-05-07 11:37:07] local.NOTICE: Monitoring start {\"correlation_id\":\"64decce4-a339-4c1b-8a73-4f612ef2eea2\",\"trace_id\":\"07e59e6c-d681-41f9-ba04-5cab00e9a754\"}\n[2026-05-07 11:37:07] local.NOTICE: Monitoring end {\"correlation_id\":\"64decce4-a339-4c1b-8a73-4f612ef2eea2\",\"trace_id\":\"07e59e6c-d681-41f9-ba04-5cab00e9a754\"}\n[2026-05-07 11:37:09] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":62.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"0326b1c8-69ac-4d09-aae5-e808abc71f46\",\"trace_id\":\"2d16668b-26b0-44cf-a533-493500255667\"}\n[2026-05-07 11:37:09] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":62.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"0326b1c8-69ac-4d09-aae5-e808abc71f46\",\"trace_id\":\"2d16668b-26b0-44cf-a533-493500255667\"}\n[2026-05-07 11:37:10] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":62.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"aa512302-070c-4f99-b3ef-1a43c71b6297\",\"trace_id\":\"9e5c4036-6a42-4c64-a9b3-f11143254293\"}\n[2026-05-07 11:37:10] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"aa512302-070c-4f99-b3ef-1a43c71b6297\",\"trace_id\":\"9e5c4036-6a42-4c64-a9b3-f11143254293\"}\n[2026-05-07 11:37:10] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"aa512302-070c-4f99-b3ef-1a43c71b6297\",\"trace_id\":\"9e5c4036-6a42-4c64-a9b3-f11143254293\"}\n[2026-05-07 11:37:10] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":62.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"aa512302-070c-4f99-b3ef-1a43c71b6297\",\"trace_id\":\"9e5c4036-6a42-4c64-a9b3-f11143254293\"}\n[2026-05-07 11:37:13] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:create\",\"memoryBeforeCommandInMb\":62.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"b3d4318e-3db2-413c-8fe1-8827ec834020\",\"trace_id\":\"870e454c-3a47-419e-88f1-2321d38b8937\"}\n[2026-05-07 11:37:13] local.INFO: [EmailSchedule] STARTING batch create {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"b3d4318e-3db2-413c-8fe1-8827ec834020\",\"trace_id\":\"870e454c-3a47-419e-88f1-2321d38b8937\"}\n[2026-05-07 11:37:13] local.INFO: [EmailSchedule] FINISHED batch create {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"b3d4318e-3db2-413c-8fe1-8827ec834020\",\"trace_id\":\"870e454c-3a47-419e-88f1-2321d38b8937\"}\n[2026-05-07 11:37:13] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:create\",\"memoryBeforeCommandInMb\":62.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"b3d4318e-3db2-413c-8fe1-8827ec834020\",\"trace_id\":\"870e454c-3a47-419e-88f1-2321d38b8937\"}\n[2026-05-07 11:37:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"activity:sync\",\"memoryBeforeCommandInMb\":62.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"3e5f2a44-295d-4c28-b5e9-1a649c1f49ae\",\"trace_id\":\"f4d85ec2-b1d2-4418-bb65-814c209e628f\"}\n[2026-05-07 11:37:15] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"activity:sync\",\"memoryBeforeCommandInMb\":62.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"3e5f2a44-295d-4c28-b5e9-1a649c1f49ae\",\"trace_id\":\"f4d85ec2-b1d2-4418-bb65-814c209e628f\"}\n[2026-05-07 11:37:21] local.INFO: [Commands/AsyncUpdateEsEntities] Starting ES update worker {\"pid\":20519,\"workerId\":\"\",\"target\":\"activities\"} {\"correlation_id\":\"1a81e470-75ac-4728-9d45-9f879fc96c5b\",\"trace_id\":\"7184ea88-9f01-42bc-9508-8e4ad0c1204b\"}\n[2026-05-07 11:37:22] local.INFO: [Jiminny\\Jobs\\Mailbox\\CreateBatches] processed 2 inboxes and created 0 batches {\"userId\":null,\"batchSize\":30,\"maxBatches\":1000} {\"correlation_id\":\"798a3e91-233c-4b61-aa8e-80a7b84ac45f\",\"trace_id\":\"870e454c-3a47-419e-88f1-2321d38b8937\"}\n[2026-05-07 11:37:53] local.INFO: [Commands/AsyncUpdateEsEntities] Starting ES update worker {\"pid\":20661,\"workerId\":\"\",\"target\":\"activities\"} {\"correlation_id\":\"293fa4a8-dc12-452e-88a3-f7408f8ed676\",\"trace_id\":\"e3d77ea8-2ff3-4b4e-a388-8f21192e51f3\"}\n[2026-05-07 11:38:03] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"crm:sync-opportunity\",\"memoryBeforeCommandInMb\":62.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"eb6c1736-f06b-4fbc-80f1-e1283f2021fb\",\"trace_id\":\"cef5d248-2fbf-443a-915a-81470cec6a21\"}\n[2026-05-07 11:38:04] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"eb6c1736-f06b-4fbc-80f1-e1283f2021fb\",\"trace_id\":\"cef5d248-2fbf-443a-915a-81470cec6a21\"}\n[2026-05-07 11:38:04] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"eb6c1736-f06b-4fbc-80f1-e1283f2021fb\",\"trace_id\":\"cef5d248-2fbf-443a-915a-81470cec6a21\"}\n[2026-05-07 11:38:04] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"eb6c1736-f06b-4fbc-80f1-e1283f2021fb\",\"trace_id\":\"cef5d248-2fbf-443a-915a-81470cec6a21\"}\n[2026-05-07 11:38:04] local.INFO: [HubSpot] Syncing opportunities using strategy: lastModified {\"team\":2} {\"correlation_id\":\"eb6c1736-f06b-4fbc-80f1-e1283f2021fb\",\"trace_id\":\"cef5d248-2fbf-443a-915a-81470cec6a21\"}\n[2026-05-07 11:38:04] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/deals/search\",\"total_requests\":1,\"total_records_fetched\":6,\"total_elapsed_seconds\":0.56,\"average_seconds_per_request\":0.56} {\"correlation_id\":\"eb6c1736-f06b-4fbc-80f1-e1283f2021fb\",\"trace_id\":\"cef5d248-2fbf-443a-915a-81470cec6a21\"}","depth":4,"bounds":{"left":0.52859044,"top":0.0726257,"width":0.45977393,"height":0.9273743},"on_screen":true,"value":"[2026-05-07 11:36:44] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"crm:sync-opportunity\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"462baf35-d312-4641-9896-e8b15e8fdb82\",\"trace_id\":\"aeb070fe-166a-48bf-99c0-acfcbfb40c1b\"}\n[2026-05-07 11:36:44] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"462baf35-d312-4641-9896-e8b15e8fdb82\",\"trace_id\":\"aeb070fe-166a-48bf-99c0-acfcbfb40c1b\"}\n[2026-05-07 11:36:44] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"462baf35-d312-4641-9896-e8b15e8fdb82\",\"trace_id\":\"aeb070fe-166a-48bf-99c0-acfcbfb40c1b\"}\n[2026-05-07 11:36:44] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"462baf35-d312-4641-9896-e8b15e8fdb82\",\"trace_id\":\"aeb070fe-166a-48bf-99c0-acfcbfb40c1b\"}\n[2026-05-07 11:36:44] local.INFO: [HubSpot] Syncing opportunities using strategy: lastModified {\"team\":2} {\"correlation_id\":\"462baf35-d312-4641-9896-e8b15e8fdb82\",\"trace_id\":\"aeb070fe-166a-48bf-99c0-acfcbfb40c1b\"}\n[2026-05-07 11:36:45] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/deals/search\",\"total_requests\":1,\"total_records_fetched\":6,\"total_elapsed_seconds\":0.48,\"average_seconds_per_request\":0.48} {\"correlation_id\":\"462baf35-d312-4641-9896-e8b15e8fdb82\",\"trace_id\":\"aeb070fe-166a-48bf-99c0-acfcbfb40c1b\"}\n[2026-05-07 11:36:46] local.INFO: [HubSpot] importOpportunityBatch timing {\"teamId\":2,\"deal_count\":6,\"total_ms\":659,\"company_assoc_api_ms\":276,\"contact_assoc_api_ms\":203,\"prepare_entities_ms\":19,\"prepare_accounts_ms\":3,\"prepare_contacts_ms\":17,\"total_companies\":5,\"missing_companies\":0,\"total_contacts\":23,\"missing_contacts\":0,\"deals_loop_ms\":152,\"avg_deal_ms\":25,\"slow_deals_count\":0,\"slow_deals\":[]} {\"correlation_id\":\"462baf35-d312-4641-9896-e8b15e8fdb82\",\"trace_id\":\"aeb070fe-166a-48bf-99c0-acfcbfb40c1b\"}\n[2026-05-07 11:36:46] local.INFO: [HubSpot] Synced opportunities {\"team\":2,\"strategies\":\"lastModified\",\"sync_count\":5,\"total\":6,\"last_synced_id\":\"297846423\",\"duration_ms\":1161.39} {\"correlation_id\":\"462baf35-d312-4641-9896-e8b15e8fdb82\",\"trace_id\":\"aeb070fe-166a-48bf-99c0-acfcbfb40c1b\"}\n[2026-05-07 11:36:46] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"crm:sync-opportunity\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"462baf35-d312-4641-9896-e8b15e8fdb82\",\"trace_id\":\"aeb070fe-166a-48bf-99c0-acfcbfb40c1b\"}\n[2026-05-07 11:36:52] local.INFO: [HubSpot Journal Polling] Getting offset from database {\"offset\":\"\",\"jiminny_team_id\":1} {\"correlation_id\":\"8568abe7-be33-417c-aa2f-b1bd53fb4adc\",\"trace_id\":\"582bff07-5ea4-4469-8ca8-efa41b04d46d\"}\n[2026-05-07 11:36:52] local.INFO: [HubSpot Journal API] Fetching latest journal entry {\"url\":\"https://api.hubapi.com/webhooks/v4/journal/latest\"} {\"correlation_id\":\"8568abe7-be33-417c-aa2f-b1bd53fb4adc\",\"trace_id\":\"582bff07-5ea4-4469-8ca8-efa41b04d46d\"}\n[2026-05-07 11:36:52] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"8568abe7-be33-417c-aa2f-b1bd53fb4adc\",\"trace_id\":\"582bff07-5ea4-4469-8ca8-efa41b04d46d\"}\n[2026-05-07 11:36:52] local.WARNING: [HubSpot Journal Polling] Maximum empty results reached, stopping {\"empty_results\":5,\"max_empty_results\":5} {\"correlation_id\":\"8568abe7-be33-417c-aa2f-b1bd53fb4adc\",\"trace_id\":\"582bff07-5ea4-4469-8ca8-efa41b04d46d\"}\n[2026-05-07 11:36:52] local.WARNING: [HubSpot Journal Polling] Maximum empty results reached, stopping {\"empty_results\":5,\"max_empty_results\":5} {\"correlation_id\":\"8568abe7-be33-417c-aa2f-b1bd53fb4adc\",\"trace_id\":\"582bff07-5ea4-4469-8ca8-efa41b04d46d\"}\n[2026-05-07 11:36:52] local.INFO: [HubSpot Journal Polling] Service ending {\"runtime_seconds\":56,\"total_cycles\":5,\"files_downloaded\":0,\"empty_files\":0,\"other_portal_skipped\":0,\"total_events\":0,\"events_per_file\":0,\"avg_api_ms\":176.5,\"avg_download_ms\":0.0,\"avg_transform_ms\":0.0,\"avg_process_ms\":0.0,\"peak_memory_mb\":99.73} {\"correlation_id\":\"8568abe7-be33-417c-aa2f-b1bd53fb4adc\",\"trace_id\":\"582bff07-5ea4-4469-8ca8-efa41b04d46d\"}\n[2026-05-07 11:36:52] local.INFO: [HubSpot Journal Polling] Released polling lock {\"correlation_id\":\"8568abe7-be33-417c-aa2f-b1bd53fb4adc\",\"trace_id\":\"582bff07-5ea4-4469-8ca8-efa41b04d46d\"}\n[2026-05-07 11:37:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"34ae70b9-ee92-4e0c-bb97-3ecc204278be\",\"trace_id\":\"0d02e69d-5e33-4059-938c-d41350a39b72\"}\n[2026-05-07 11:37:05] local.INFO: [ScheduleBotCommand] Number of activities to be captured: 0 {\"correlation_id\":\"34ae70b9-ee92-4e0c-bb97-3ecc204278be\",\"trace_id\":\"0d02e69d-5e33-4059-938c-d41350a39b72\"}\n[2026-05-07 11:37:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"34ae70b9-ee92-4e0c-bb97-3ecc204278be\",\"trace_id\":\"0d02e69d-5e33-4059-938c-d41350a39b72\"}\n[2026-05-07 11:37:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":62.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"6052f7ad-dde1-41de-8051-5ba8d54babdd\",\"trace_id\":\"2e216848-ddf9-4f8c-8808-93a09cef8f5f\"}\n[2026-05-07 11:37:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":62.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"6052f7ad-dde1-41de-8051-5ba8d54babdd\",\"trace_id\":\"2e216848-ddf9-4f8c-8808-93a09cef8f5f\"}\n[2026-05-07 11:37:07] local.NOTICE: Monitoring start {\"correlation_id\":\"64decce4-a339-4c1b-8a73-4f612ef2eea2\",\"trace_id\":\"07e59e6c-d681-41f9-ba04-5cab00e9a754\"}\n[2026-05-07 11:37:07] local.NOTICE: Monitoring end {\"correlation_id\":\"64decce4-a339-4c1b-8a73-4f612ef2eea2\",\"trace_id\":\"07e59e6c-d681-41f9-ba04-5cab00e9a754\"}\n[2026-05-07 11:37:09] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":62.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"0326b1c8-69ac-4d09-aae5-e808abc71f46\",\"trace_id\":\"2d16668b-26b0-44cf-a533-493500255667\"}\n[2026-05-07 11:37:09] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":62.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"0326b1c8-69ac-4d09-aae5-e808abc71f46\",\"trace_id\":\"2d16668b-26b0-44cf-a533-493500255667\"}\n[2026-05-07 11:37:10] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":62.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"aa512302-070c-4f99-b3ef-1a43c71b6297\",\"trace_id\":\"9e5c4036-6a42-4c64-a9b3-f11143254293\"}\n[2026-05-07 11:37:10] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"aa512302-070c-4f99-b3ef-1a43c71b6297\",\"trace_id\":\"9e5c4036-6a42-4c64-a9b3-f11143254293\"}\n[2026-05-07 11:37:10] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"aa512302-070c-4f99-b3ef-1a43c71b6297\",\"trace_id\":\"9e5c4036-6a42-4c64-a9b3-f11143254293\"}\n[2026-05-07 11:37:10] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":62.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"aa512302-070c-4f99-b3ef-1a43c71b6297\",\"trace_id\":\"9e5c4036-6a42-4c64-a9b3-f11143254293\"}\n[2026-05-07 11:37:13] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:create\",\"memoryBeforeCommandInMb\":62.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"b3d4318e-3db2-413c-8fe1-8827ec834020\",\"trace_id\":\"870e454c-3a47-419e-88f1-2321d38b8937\"}\n[2026-05-07 11:37:13] local.INFO: [EmailSchedule] STARTING batch create {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"b3d4318e-3db2-413c-8fe1-8827ec834020\",\"trace_id\":\"870e454c-3a47-419e-88f1-2321d38b8937\"}\n[2026-05-07 11:37:13] local.INFO: [EmailSchedule] FINISHED batch create {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"b3d4318e-3db2-413c-8fe1-8827ec834020\",\"trace_id\":\"870e454c-3a47-419e-88f1-2321d38b8937\"}\n[2026-05-07 11:37:13] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:create\",\"memoryBeforeCommandInMb\":62.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"b3d4318e-3db2-413c-8fe1-8827ec834020\",\"trace_id\":\"870e454c-3a47-419e-88f1-2321d38b8937\"}\n[2026-05-07 11:37:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"activity:sync\",\"memoryBeforeCommandInMb\":62.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"3e5f2a44-295d-4c28-b5e9-1a649c1f49ae\",\"trace_id\":\"f4d85ec2-b1d2-4418-bb65-814c209e628f\"}\n[2026-05-07 11:37:15] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"activity:sync\",\"memoryBeforeCommandInMb\":62.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"3e5f2a44-295d-4c28-b5e9-1a649c1f49ae\",\"trace_id\":\"f4d85ec2-b1d2-4418-bb65-814c209e628f\"}\n[2026-05-07 11:37:21] local.INFO: [Commands/AsyncUpdateEsEntities] Starting ES update worker {\"pid\":20519,\"workerId\":\"\",\"target\":\"activities\"} {\"correlation_id\":\"1a81e470-75ac-4728-9d45-9f879fc96c5b\",\"trace_id\":\"7184ea88-9f01-42bc-9508-8e4ad0c1204b\"}\n[2026-05-07 11:37:22] local.INFO: [Jiminny\\Jobs\\Mailbox\\CreateBatches] processed 2 inboxes and created 0 batches {\"userId\":null,\"batchSize\":30,\"maxBatches\":1000} {\"correlation_id\":\"798a3e91-233c-4b61-aa8e-80a7b84ac45f\",\"trace_id\":\"870e454c-3a47-419e-88f1-2321d38b8937\"}\n[2026-05-07 11:37:53] local.INFO: [Commands/AsyncUpdateEsEntities] Starting ES update worker {\"pid\":20661,\"workerId\":\"\",\"target\":\"activities\"} {\"correlation_id\":\"293fa4a8-dc12-452e-88a3-f7408f8ed676\",\"trace_id\":\"e3d77ea8-2ff3-4b4e-a388-8f21192e51f3\"}\n[2026-05-07 11:38:03] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"crm:sync-opportunity\",\"memoryBeforeCommandInMb\":62.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"eb6c1736-f06b-4fbc-80f1-e1283f2021fb\",\"trace_id\":\"cef5d248-2fbf-443a-915a-81470cec6a21\"}\n[2026-05-07 11:38:04] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"eb6c1736-f06b-4fbc-80f1-e1283f2021fb\",\"trace_id\":\"cef5d248-2fbf-443a-915a-81470cec6a21\"}\n[2026-05-07 11:38:04] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"eb6c1736-f06b-4fbc-80f1-e1283f2021fb\",\"trace_id\":\"cef5d248-2fbf-443a-915a-81470cec6a21\"}\n[2026-05-07 11:38:04] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"eb6c1736-f06b-4fbc-80f1-e1283f2021fb\",\"trace_id\":\"cef5d248-2fbf-443a-915a-81470cec6a21\"}\n[2026-05-07 11:38:04] local.INFO: [HubSpot] Syncing opportunities using strategy: lastModified {\"team\":2} {\"correlation_id\":\"eb6c1736-f06b-4fbc-80f1-e1283f2021fb\",\"trace_id\":\"cef5d248-2fbf-443a-915a-81470cec6a21\"}\n[2026-05-07 11:38:04] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/deals/search\",\"total_requests\":1,\"total_records_fetched\":6,\"total_elapsed_seconds\":0.56,\"average_seconds_per_request\":0.56} {\"correlation_id\":\"eb6c1736-f06b-4fbc-80f1-e1283f2021fb\",\"trace_id\":\"cef5d248-2fbf-443a-915a-81470cec6a21\"}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.007978723,"height":0.0},"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"60","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.010305851,"height":0.0},"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.00731383,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.006981383,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Component\\Utility\\Service\\ProviderRateLimiter;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n private ProviderRateLimiter $rateLimiter;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager,\n ProviderRateLimiter $rateLimiter,\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n $this->rateLimiter = $rateLimiter;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Single entry point for every HubSpot API call. Enforces the per-portal\n * rate limit configured in the rate_limits table (morphed to the current\n * Configuration) and reacts to a real 429 from HubSpot by translating it\n * into a RateLimitException carrying Retry-After.\n *\n * Wrap any outbound HubSpot call (SDK or raw HTTP) like:\n *\n * $this->executeRequest(fn () => $this->getNewInstance()->crm()->...);\n *\n * @template T\n * @param callable(): T $apiCall\n * @return T\n *\n * @throws RateLimitException\n */\n private function executeRequest(callable $apiCall)\n {\n if (! $this->rateLimiter->canMakeRequest($this->config)) {\n $retryAfter = $this->rateLimiter->requestAvailableIn($this->config);\n\n $this->log->warning('[Hubspot] Rate limit exceeded, deferring request', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n ]);\n\n throw new RateLimitException(\n 'Hubspot rate limit reached for configuration ' . $this->config->getId(),\n $retryAfter,\n );\n }\n\n $this->rateLimiter->incrementRequestCount($this->config);\n\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n private function isHubspotRateLimit(Throwable $e): bool\n {\n return method_exists($e, 'getCode') && (int) $e->getCode() === 429;\n }\n\n private function parseRetryAfter(Throwable $e): int\n {\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n return 10;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n ));\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n $response = $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n $response = $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n\n $max = $response->getHeaderLine('X-HubSpot-RateLimit-Max'); // \"110\"\n $remaining = $response->getHeaderLine('X-HubSpot-RateLimit-Remaining'); // \"109\"\n $interval = $response->getHeaderLine('X-HubSpot-RateLimit-Interval-Milliseconds'); // \"10000\"\n $body = json_decode((string) $response->getBody(), true);\n\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$max ' . PHP_EOL . print_r($max, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$remaining ' . PHP_EOL . print_r($remaining, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$interval ' . PHP_EOL . print_r($interval, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$body ' . PHP_EOL . print_r($body, true));\n\n return $response;\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Component\\Utility\\Service\\ProviderRateLimiter;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n private ProviderRateLimiter $rateLimiter;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager,\n ProviderRateLimiter $rateLimiter,\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n $this->rateLimiter = $rateLimiter;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Single entry point for every HubSpot API call. Enforces the per-portal\n * rate limit configured in the rate_limits table (morphed to the current\n * Configuration) and reacts to a real 429 from HubSpot by translating it\n * into a RateLimitException carrying Retry-After.\n *\n * Wrap any outbound HubSpot call (SDK or raw HTTP) like:\n *\n * $this->executeRequest(fn () => $this->getNewInstance()->crm()->...);\n *\n * @template T\n * @param callable(): T $apiCall\n * @return T\n *\n * @throws RateLimitException\n */\n private function executeRequest(callable $apiCall)\n {\n if (! $this->rateLimiter->canMakeRequest($this->config)) {\n $retryAfter = $this->rateLimiter->requestAvailableIn($this->config);\n\n $this->log->warning('[Hubspot] Rate limit exceeded, deferring request', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n ]);\n\n throw new RateLimitException(\n 'Hubspot rate limit reached for configuration ' . $this->config->getId(),\n $retryAfter,\n );\n }\n\n $this->rateLimiter->incrementRequestCount($this->config);\n\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n private function isHubspotRateLimit(Throwable $e): bool\n {\n return method_exists($e, 'getCode') && (int) $e->getCode() === 429;\n }\n\n private function parseRetryAfter(Throwable $e): int\n {\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n return 10;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n ));\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n $response = $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n $response = $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n\n $max = $response->getHeaderLine('X-HubSpot-RateLimit-Max'); // \"110\"\n $remaining = $response->getHeaderLine('X-HubSpot-RateLimit-Remaining'); // \"109\"\n $interval = $response->getHeaderLine('X-HubSpot-RateLimit-Interval-Milliseconds'); // \"10000\"\n $body = json_decode((string) $response->getBody(), true);\n\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$max ' . PHP_EOL . print_r($max, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$remaining ' . PHP_EOL . print_r($remaining, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$interval ' . PHP_EOL . print_r($interval, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$body ' . PHP_EOL . print_r($body, true));\n\n return $response;\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.011968086,"top":0.047885075,"width":0.024268618,"height":0.024740623},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-2199466652252128033
|
6666989725209335916
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
[2026-05-07 11:36:44] local.INFO: Jiminny\Console\Commands\Command::run Memory usage before starting command {"command":"crm:sync-opportunity","memoryBeforeCommandInMb":60.0,"memoryPeakBeforeCommandInMb":99.727} {"correlation_id":"462baf35-d312-4641-9896-e8b15e8fdb82","trace_id":"aeb070fe-166a-48bf-99c0-acfcbfb40c1b"}
[2026-05-07 11:36:44] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"462baf35-d312-4641-9896-e8b15e8fdb82","trace_id":"aeb070fe-166a-48bf-99c0-acfcbfb40c1b"}
[2026-05-07 11:36:44] local.INFO: [SocialAccountService] Token retrieved {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"462baf35-d312-4641-9896-e8b15e8fdb82","trace_id":"aeb070fe-166a-48bf-99c0-acfcbfb40c1b"}
[2026-05-07 11:36:44] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"462baf35-d312-4641-9896-e8b15e8fdb82","trace_id":"aeb070fe-166a-48bf-99c0-acfcbfb40c1b"}
[2026-05-07 11:36:44] local.INFO: [HubSpot] Syncing opportunities using strategy: lastModified {"team":2} {"correlation_id":"462baf35-d312-4641-9896-e8b15e8fdb82","trace_id":"aeb070fe-166a-48bf-99c0-acfcbfb40c1b"}
[2026-05-07 11:36:45] local.INFO: [Hubspot] Pagination completed {"team_id":2,"endpoint":"[URL_WITH_CREDENTIALS] CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall
* @return T
*
* @throws RateLimitException
*/
private function executeRequest(callable $apiCall)
{
if (! $this->rateLimiter->canMakeRequest($this->config)) {
$retryAfter = $this->rateLimiter->requestAvailableIn($this->config);
$this->log->warning('[Hubspot] Rate limit exceeded, deferring request', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
]);
throw new RateLimitException(
'Hubspot rate limit reached for configuration ' . $this->config->getId(),
$retryAfter,
);
}
$this->rateLimiter->incrementRequestCount($this->config);
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
private function isHubspotRateLimit(Throwable $e): bool
{
return method_exists($e, 'getCode') && (int) $e->getCode() === 429;
}
private function parseRetryAfter(Throwable $e): int
{
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
return 10;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
$deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
));
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
$response = $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
$response = $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
$max = $response->getHeaderLine('X-HubSpot-RateLimit-Max'); // "110"
$remaining = $response->getHeaderLine('X-HubSpot-RateLimit-Remaining'); // "109"
$interval = $response->getHeaderLine('X-HubSpot-RateLimit-Interval-Milliseconds'); // "10000"
$body = json_decode((string) $response->getBody(), true);
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$max ' . PHP_EOL . print_r($max, true));
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$remaining ' . PHP_EOL . print_r($remaining, true));
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$interval ' . PHP_EOL . print_r($interval, true));
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$body ' . PHP_EOL . print_r($body, true));
return $response;
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
2744
|
111
|
43
|
2026-05-07T11:38:09.493606+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-07/1778 /Users/lukas/.screenpipe/data/data/2026-05-07/1778153889493_m1.jpg...
|
PhpStorm
|
faVsco.js – Hubspot/Client.php
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
Editor for custom.log
Sync Changes
Hide This Notification
Code changed:
Hide
2
60
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot;
use HubSpot\Client\Crm\Deals\ApiException as DealApiException;
use HubSpot\Client\Crm\Contacts\ApiException as ContactApiException;
use HubSpot\Client\Crm\Companies\ApiException as CompanyApiException;
use HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectWithAssociations as ContactsWithAssociations;
use HubSpot\Client\Crm\Companies\Model\SimplePublicObjectWithAssociations as CompaniesWithAssociations;
use HubSpot\Client\Crm\Deals\Model\SimplePublicObjectWithAssociations as DealWithAssociations;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectInput;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectWithAssociations as ObjectWithAssociations;
use HubSpot\Client\Crm\Pipelines\Model\Error;
use HubSpot\Client\Crm\Pipelines\Model\PipelineStage;
use HubSpot\Client\Crm\Properties\Model\Property;
use HubSpot\Discovery\Discovery;
use Jiminny\Component\Utility\Service\ProviderRateLimiter;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Crm\Field;
use Jiminny\Services\Crm\BaseClient;
use Jiminny\Services\Crm\Hubspot\DTO\Response\Owner;
use Jiminny\Services\SocialAccountService;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use SevenShores\Hubspot\Factory;
use SevenShores\Hubspot\Http\Response;
use Jiminny\Services\Crm\Hubspot\Pagination\HubspotPaginationService;
use Throwable;
/**
* @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall
* @return T
*
* @throws RateLimitException
*/
private function executeRequest(callable $apiCall)
{
if (! $this->rateLimiter->canMakeRequest($this->config)) {
$retryAfter = $this->rateLimiter->requestAvailableIn($this->config);
$this->log->warning('[Hubspot] Rate limit exceeded, deferring request', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
]);
throw new RateLimitException(
'Hubspot rate limit reached for configuration ' . $this->config->getId(),
$retryAfter,
);
}
$this->rateLimiter->incrementRequestCount($this->config);
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
private function isHubspotRateLimit(Throwable $e): bool
{
return method_exists($e, 'getCode') && (int) $e->getCode() === 429;
}
private function parseRetryAfter(Throwable $e): int
{
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
return 10;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
$deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
));
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
$response = $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
$response = $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
$max = $response->getHeaderLine('X-HubSpot-RateLimit-Max'); // "110"
$remaining = $response->getHeaderLine('X-HubSpot-RateLimit-Remaining'); // "109"
$interval = $response->getHeaderLine('X-HubSpot-RateLimit-Interval-Milliseconds'); // "10000"
$body = json_decode((string) $response->getBody(), true);
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$max ' . PHP_EOL . print_r($max, true));
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$remaining ' . PHP_EOL . print_r($remaining, true));
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$interval ' . PHP_EOL . print_r($interval, true));
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$body ' . PHP_EOL . print_r($body, true));
return $response;
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"on_screen":true,"help_text":"Git Branch: master","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"Editor for custom.log","depth":4,"on_screen":true,"role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.016666668,"height":0.02111111},"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"60","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.021527778,"height":0.02111111},"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.015277778,"height":0.025555555},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.014583333,"height":0.025555555},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Component\\Utility\\Service\\ProviderRateLimiter;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n private ProviderRateLimiter $rateLimiter;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager,\n ProviderRateLimiter $rateLimiter,\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n $this->rateLimiter = $rateLimiter;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Single entry point for every HubSpot API call. Enforces the per-portal\n * rate limit configured in the rate_limits table (morphed to the current\n * Configuration) and reacts to a real 429 from HubSpot by translating it\n * into a RateLimitException carrying Retry-After.\n *\n * Wrap any outbound HubSpot call (SDK or raw HTTP) like:\n *\n * $this->executeRequest(fn () => $this->getNewInstance()->crm()->...);\n *\n * @template T\n * @param callable(): T $apiCall\n * @return T\n *\n * @throws RateLimitException\n */\n private function executeRequest(callable $apiCall)\n {\n if (! $this->rateLimiter->canMakeRequest($this->config)) {\n $retryAfter = $this->rateLimiter->requestAvailableIn($this->config);\n\n $this->log->warning('[Hubspot] Rate limit exceeded, deferring request', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n ]);\n\n throw new RateLimitException(\n 'Hubspot rate limit reached for configuration ' . $this->config->getId(),\n $retryAfter,\n );\n }\n\n $this->rateLimiter->incrementRequestCount($this->config);\n\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n private function isHubspotRateLimit(Throwable $e): bool\n {\n return method_exists($e, 'getCode') && (int) $e->getCode() === 429;\n }\n\n private function parseRetryAfter(Throwable $e): int\n {\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n return 10;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n ));\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n $response = $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n $response = $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n\n $max = $response->getHeaderLine('X-HubSpot-RateLimit-Max'); // \"110\"\n $remaining = $response->getHeaderLine('X-HubSpot-RateLimit-Remaining'); // \"109\"\n $interval = $response->getHeaderLine('X-HubSpot-RateLimit-Interval-Milliseconds'); // \"10000\"\n $body = json_decode((string) $response->getBody(), true);\n\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$max ' . PHP_EOL . print_r($max, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$remaining ' . PHP_EOL . print_r($remaining, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$interval ' . PHP_EOL . print_r($interval, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$body ' . PHP_EOL . print_r($body, true));\n\n return $response;\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Component\\Utility\\Service\\ProviderRateLimiter;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n private ProviderRateLimiter $rateLimiter;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager,\n ProviderRateLimiter $rateLimiter,\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n $this->rateLimiter = $rateLimiter;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Single entry point for every HubSpot API call. Enforces the per-portal\n * rate limit configured in the rate_limits table (morphed to the current\n * Configuration) and reacts to a real 429 from HubSpot by translating it\n * into a RateLimitException carrying Retry-After.\n *\n * Wrap any outbound HubSpot call (SDK or raw HTTP) like:\n *\n * $this->executeRequest(fn () => $this->getNewInstance()->crm()->...);\n *\n * @template T\n * @param callable(): T $apiCall\n * @return T\n *\n * @throws RateLimitException\n */\n private function executeRequest(callable $apiCall)\n {\n if (! $this->rateLimiter->canMakeRequest($this->config)) {\n $retryAfter = $this->rateLimiter->requestAvailableIn($this->config);\n\n $this->log->warning('[Hubspot] Rate limit exceeded, deferring request', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n ]);\n\n throw new RateLimitException(\n 'Hubspot rate limit reached for configuration ' . $this->config->getId(),\n $retryAfter,\n );\n }\n\n $this->rateLimiter->incrementRequestCount($this->config);\n\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n private function isHubspotRateLimit(Throwable $e): bool\n {\n return method_exists($e, 'getCode') && (int) $e->getCode() === 429;\n }\n\n private function parseRetryAfter(Throwable $e): int\n {\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n return 10;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n ));\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n $response = $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n $response = $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n\n $max = $response->getHeaderLine('X-HubSpot-RateLimit-Max'); // \"110\"\n $remaining = $response->getHeaderLine('X-HubSpot-RateLimit-Remaining'); // \"109\"\n $interval = $response->getHeaderLine('X-HubSpot-RateLimit-Interval-Milliseconds'); // \"10000\"\n $body = json_decode((string) $response->getBody(), true);\n\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$max ' . PHP_EOL . print_r($max, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$remaining ' . PHP_EOL . print_r($remaining, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$interval ' . PHP_EOL . print_r($interval, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$body ' . PHP_EOL . print_r($body, true));\n\n return $response;\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-188086479456983350
|
6378757184196315236
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
Editor for custom.log
Sync Changes
Hide This Notification
Code changed:
Hide
2
60
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot;
use HubSpot\Client\Crm\Deals\ApiException as DealApiException;
use HubSpot\Client\Crm\Contacts\ApiException as ContactApiException;
use HubSpot\Client\Crm\Companies\ApiException as CompanyApiException;
use HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectWithAssociations as ContactsWithAssociations;
use HubSpot\Client\Crm\Companies\Model\SimplePublicObjectWithAssociations as CompaniesWithAssociations;
use HubSpot\Client\Crm\Deals\Model\SimplePublicObjectWithAssociations as DealWithAssociations;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectInput;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectWithAssociations as ObjectWithAssociations;
use HubSpot\Client\Crm\Pipelines\Model\Error;
use HubSpot\Client\Crm\Pipelines\Model\PipelineStage;
use HubSpot\Client\Crm\Properties\Model\Property;
use HubSpot\Discovery\Discovery;
use Jiminny\Component\Utility\Service\ProviderRateLimiter;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Crm\Field;
use Jiminny\Services\Crm\BaseClient;
use Jiminny\Services\Crm\Hubspot\DTO\Response\Owner;
use Jiminny\Services\SocialAccountService;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use SevenShores\Hubspot\Factory;
use SevenShores\Hubspot\Http\Response;
use Jiminny\Services\Crm\Hubspot\Pagination\HubspotPaginationService;
use Throwable;
/**
* @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall
* @return T
*
* @throws RateLimitException
*/
private function executeRequest(callable $apiCall)
{
if (! $this->rateLimiter->canMakeRequest($this->config)) {
$retryAfter = $this->rateLimiter->requestAvailableIn($this->config);
$this->log->warning('[Hubspot] Rate limit exceeded, deferring request', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
]);
throw new RateLimitException(
'Hubspot rate limit reached for configuration ' . $this->config->getId(),
$retryAfter,
);
}
$this->rateLimiter->incrementRequestCount($this->config);
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
private function isHubspotRateLimit(Throwable $e): bool
{
return method_exists($e, 'getCode') && (int) $e->getCode() === 429;
}
private function parseRetryAfter(Throwable $e): int
{
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
return 10;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
$deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
));
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
$response = $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
$response = $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
$max = $response->getHeaderLine('X-HubSpot-RateLimit-Max'); // "110"
$remaining = $response->getHeaderLine('X-HubSpot-RateLimit-Remaining'); // "109"
$interval = $response->getHeaderLine('X-HubSpot-RateLimit-Interval-Milliseconds'); // "10000"
$body = json_decode((string) $response->getBody(), true);
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$max ' . PHP_EOL . print_r($max, true));
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$remaining ' . PHP_EOL . print_r($remaining, true));
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$interval ' . PHP_EOL . print_r($interval, true));
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$body ' . PHP_EOL . print_r($body, true));
return $response;
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
2854
|
114
|
43
|
2026-05-07T11:43:37.787881+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-07/1778 /Users/lukas/.screenpipe/data/data/2026-05-07/1778154217787_m2.jpg...
|
PhpStorm
|
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Find in Files
97 matches in 21 files
File mask:
*. Find in Files
97 matches in 21 files
File mask:
*.php
*.php
Auto
*.php
Filter Search Results
Pin Window
Search History
makeRequest
New Line
Match case
Words
Regex
Replace History
Replace
New Line
Preserve case
In Project
Module
Directory
Scope
Module
/Users/lukas/jiminny/app/app/Services/Crm/Hubspot
/Users/lukas/jiminny/app/app/Services/Crm/Hubspot
/Users/lukas/jiminny/app/app/Exceptions
/Users/lukas/jiminny/app/app/Listeners/Crm
/Users/lukas/jiminny/app/app/Component/Queue/Job
/Users/lukas/jiminny/app/app/Listeners/AutomatedReports/UserPilot
/Users/lukas/jiminny/app/app/Events/Crm
/Users/lukas/jiminny/app/app/Jobs/AutomatedReports
/Users/lukas/jiminny/app/app/Listeners/Activities/Coaching/UserPilot
/Users/lukas/jiminny/app/app/Listeners/Activities/ActivityProvider/UserPilot
/Users/lukas/jiminny/app/app/Jobs/Activity/PushSummaryToCrm
/Users/lukas/jiminny/app/app/Repositories/Crm
/Users/lukas/jiminny/app/app/Jobs/Crm/Delete
/Users/lukas/jiminny/app/app/Services/Kiosk/AutomatedReports
/Users/lukas/jiminny/app/app/Http/Controllers/API/UserAutomatedReports
/Users/lukas/jiminny/app/app/Services/Crm/Salesforce
/Users/lukas/jiminny/app/app/Providers
/Users/lukas/jiminny/app/app/Services/Crm/IntegrationApp
/Users/lukas/jiminny/app/app/Events/Activities/Crm
/Users/lukas/jiminny/app/app/Listeners/Playbooks
/Users/lukas/jiminny/app/app/Console/Commands/Crm
/Users/lukas/jiminny/app/app/Services/Crm
/Users/lukas/jiminny/app/app/Http/Controllers
/Users/lukas/jiminny/app/app/Console/Commands/Reports
/Users/lukas/jiminny/app/app/VO/Repository/OnDemandActivitySearch
/Users/lukas/jiminny/app/app/Listeners/Activities/Conferences/UserPilot
/Users/lukas/jiminny/app/app/Http/Controllers/Webhook
/Users/lukas/jiminny/app/resources/views/emails/reports
/Users/lukas/jiminny/app/app/Mail/Reports
/Users/lukas/jiminny/app/app/Repositories
/Users/lukas/jiminny/app/app/Component/ActivitySearch/Service
/Users/lukas/jiminny/app/tests/Unit/Services/Crm/Salesforce
/Users/lukas/jiminny/app/routes...
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"Find in Files","depth":1,"bounds":{"left":0.2992021,"top":0.12609737,"width":0.024601065,"height":0.013567438},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"97 matches in 21 files","depth":1,"bounds":{"left":0.32779256,"top":0.12609737,"width":0.044215426,"height":0.013567438},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"File mask:","depth":1,"bounds":{"left":0.5315825,"top":0.12290503,"width":0.029587766,"height":0.019952115},"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXComboBox","text":"*.php","depth":1,"bounds":{"left":0.5621675,"top":0.11971269,"width":0.027925532,"height":0.027134877},"on_screen":true,"value":"*.php","role_description":"combo box","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"*.php","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Auto","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXTextField","text":"*.php","depth":2,"bounds":{"left":0.5661569,"top":0.12609737,"width":0.011635638,"height":0.013567438},"on_screen":true,"value":"*.php","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Filter Search Results","depth":1,"bounds":{"left":0.5944149,"top":0.12290503,"width":0.00731383,"height":0.017557861},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Pin Window","depth":1,"bounds":{"left":0.6037234,"top":0.12290503,"width":0.00731383,"height":0.017557861},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Search History","depth":1,"bounds":{"left":0.2962101,"top":0.15403032,"width":0.00731383,"height":0.017557861},"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"makeRequest","depth":2,"bounds":{"left":0.30718085,"top":0.15403032,"width":0.26196808,"height":0.017557861},"on_screen":true,"value":"makeRequest","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"New Line","depth":1,"bounds":{"left":0.578125,"top":0.15403032,"width":0.00731383,"height":0.017557861},"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Match case","depth":1,"bounds":{"left":0.5880984,"top":0.15403032,"width":0.00731383,"height":0.017557861},"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Words","depth":1,"bounds":{"left":0.59674203,"top":0.15403032,"width":0.00731383,"height":0.017557861},"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Regex","depth":1,"bounds":{"left":0.60538566,"top":0.15403032,"width":0.00731383,"height":0.017557861},"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Replace History","depth":1,"bounds":{"left":0.27027926,"top":1.0,"width":0.00731383,"height":0.0},"on_screen":false,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"Replace","depth":2,"on_screen":false,"role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"New Line","depth":1,"bounds":{"left":0.27027926,"top":1.0,"width":0.00731383,"height":0.0},"on_screen":false,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Preserve case","depth":1,"bounds":{"left":0.27027926,"top":1.0,"width":0.00731383,"height":0.0},"on_screen":false,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"In Project","depth":2,"bounds":{"left":0.2992021,"top":0.1867518,"width":0.022938829,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Module","depth":2,"bounds":{"left":0.32214096,"top":0.1867518,"width":0.019281914,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Directory","depth":2,"bounds":{"left":0.3414229,"top":0.1867518,"width":0.022606382,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Scope","depth":2,"bounds":{"left":0.36402926,"top":0.1867518,"width":0.017287234,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"Module","depth":1,"bounds":{"left":0.27027926,"top":1.0,"width":0.099734046,"height":0.0},"on_screen":false,"role_description":"pop up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXComboBox","text":"/Users/lukas/jiminny/app/app/Services/Crm/Hubspot","depth":1,"bounds":{"left":0.27027926,"top":1.0,"width":0.1974734,"height":0.0},"on_screen":false,"value":"/Users/lukas/jiminny/app/app/Services/Crm/Hubspot","role_description":"combo box","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"/Users/lukas/jiminny/app/app/Services/Crm/Hubspot","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/Users/lukas/jiminny/app/app/Exceptions","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/Users/lukas/jiminny/app/app/Listeners/Crm","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/Users/lukas/jiminny/app/app/Component/Queue/Job","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/Users/lukas/jiminny/app/app/Listeners/AutomatedReports/UserPilot","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/Users/lukas/jiminny/app/app/Events/Crm","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/Users/lukas/jiminny/app/app/Jobs/AutomatedReports","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/Users/lukas/jiminny/app/app/Listeners/Activities/Coaching/UserPilot","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/Users/lukas/jiminny/app/app/Listeners/Activities/ActivityProvider/UserPilot","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/Users/lukas/jiminny/app/app/Jobs/Activity/PushSummaryToCrm","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/Users/lukas/jiminny/app/app/Repositories/Crm","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/Users/lukas/jiminny/app/app/Jobs/Crm/Delete","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/Users/lukas/jiminny/app/app/Services/Kiosk/AutomatedReports","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/Users/lukas/jiminny/app/app/Http/Controllers/API/UserAutomatedReports","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/Users/lukas/jiminny/app/app/Services/Crm/Salesforce","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/Users/lukas/jiminny/app/app/Providers","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/Users/lukas/jiminny/app/app/Services/Crm/IntegrationApp","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/Users/lukas/jiminny/app/app/Events/Activities/Crm","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/Users/lukas/jiminny/app/app/Listeners/Playbooks","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/Users/lukas/jiminny/app/app/Console/Commands/Crm","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/Users/lukas/jiminny/app/app/Services/Crm","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/Users/lukas/jiminny/app/app/Http/Controllers","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/Users/lukas/jiminny/app/app/Console/Commands/Reports","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/Users/lukas/jiminny/app/app/VO/Repository/OnDemandActivitySearch","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/Users/lukas/jiminny/app/app/Listeners/Activities/Conferences/UserPilot","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/Users/lukas/jiminny/app/app/Http/Controllers/Webhook","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/Users/lukas/jiminny/app/resources/views/emails/reports","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/Users/lukas/jiminny/app/app/Mail/Reports","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/Users/lukas/jiminny/app/app/Repositories","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/Users/lukas/jiminny/app/app/Component/ActivitySearch/Service","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/Users/lukas/jiminny/app/tests/Unit/Services/Crm/Salesforce","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/Users/lukas/jiminny/app/routes","depth":6,"on_screen":false,"role_description":"text"}]...
|
8175708703555658387
|
-882314071910824701
|
click
|
accessibility
|
NULL
|
Find in Files
97 matches in 21 files
File mask:
*. Find in Files
97 matches in 21 files
File mask:
*.php
*.php
Auto
*.php
Filter Search Results
Pin Window
Search History
makeRequest
New Line
Match case
Words
Regex
Replace History
Replace
New Line
Preserve case
In Project
Module
Directory
Scope
Module
/Users/lukas/jiminny/app/app/Services/Crm/Hubspot
/Users/lukas/jiminny/app/app/Services/Crm/Hubspot
/Users/lukas/jiminny/app/app/Exceptions
/Users/lukas/jiminny/app/app/Listeners/Crm
/Users/lukas/jiminny/app/app/Component/Queue/Job
/Users/lukas/jiminny/app/app/Listeners/AutomatedReports/UserPilot
/Users/lukas/jiminny/app/app/Events/Crm
/Users/lukas/jiminny/app/app/Jobs/AutomatedReports
/Users/lukas/jiminny/app/app/Listeners/Activities/Coaching/UserPilot
/Users/lukas/jiminny/app/app/Listeners/Activities/ActivityProvider/UserPilot
/Users/lukas/jiminny/app/app/Jobs/Activity/PushSummaryToCrm
/Users/lukas/jiminny/app/app/Repositories/Crm
/Users/lukas/jiminny/app/app/Jobs/Crm/Delete
/Users/lukas/jiminny/app/app/Services/Kiosk/AutomatedReports
/Users/lukas/jiminny/app/app/Http/Controllers/API/UserAutomatedReports
/Users/lukas/jiminny/app/app/Services/Crm/Salesforce
/Users/lukas/jiminny/app/app/Providers
/Users/lukas/jiminny/app/app/Services/Crm/IntegrationApp
/Users/lukas/jiminny/app/app/Events/Activities/Crm
/Users/lukas/jiminny/app/app/Listeners/Playbooks
/Users/lukas/jiminny/app/app/Console/Commands/Crm
/Users/lukas/jiminny/app/app/Services/Crm
/Users/lukas/jiminny/app/app/Http/Controllers
/Users/lukas/jiminny/app/app/Console/Commands/Reports
/Users/lukas/jiminny/app/app/VO/Repository/OnDemandActivitySearch
/Users/lukas/jiminny/app/app/Listeners/Activities/Conferences/UserPilot
/Users/lukas/jiminny/app/app/Http/Controllers/Webhook
/Users/lukas/jiminny/app/resources/views/emails/reports
/Users/lukas/jiminny/app/app/Mail/Reports
/Users/lukas/jiminny/app/app/Repositories
/Users/lukas/jiminny/app/app/Component/ActivitySearch/Service
/Users/lukas/jiminny/app/tests/Unit/Services/Crm/Salesforce
/Users/lukas/jiminny/app/routes...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
2855
|
113
|
43
|
2026-05-07T11:43:37.887671+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-07/1778 /Users/lukas/.screenpipe/data/data/2026-05-07/1778154217887_m1.jpg...
|
PhpStorm
|
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Find in Files
97 matches in 21 files
File mask:
*. Find in Files
97 matches in 21 files
File mask:
*.php
*.php
Auto
*.php
Filter Search Results
Pin Window
Search History
makeRequest
New Line
Match case
Words
Regex
Replace History
Replace
New Line
Preserve case
In Project
Module
Directory
Scope
Module
/Users/lukas/jiminny/app/app/Services/Crm/Hubspot
/Users/lukas/jiminny/app/app/Services/Crm/Hubspot
/Users/lukas/jiminny/app/app/Exceptions
/Users/lukas/jiminny/app/app/Listeners/Crm
/Users/lukas/jiminny/app/app/Component/Queue/Job
/Users/lukas/jiminny/app/app/Listeners/AutomatedReports/UserPilot
/Users/lukas/jiminny/app/app/Events/Crm
/Users/lukas/jiminny/app/app/Jobs/AutomatedReports
/Users/lukas/jiminny/app/app/Listeners/Activities/Coaching/UserPilot
/Users/lukas/jiminny/app/app/Listeners/Activities/ActivityProvider/UserPilot
/Users/lukas/jiminny/app/app/Jobs/Activity/PushSummaryToCrm
/Users/lukas/jiminny/app/app/Repositories/Crm
/Users/lukas/jiminny/app/app/Jobs/Crm/Delete
/Users/lukas/jiminny/app/app/Services/Kiosk/AutomatedReports
/Users/lukas/jiminny/app/app/Http/Controllers/API/UserAutomatedReports
/Users/lukas/jiminny/app/app/Services/Crm/Salesforce
/Users/lukas/jiminny/app/app/Providers
/Users/lukas/jiminny/app/app/Services/Crm/IntegrationApp
/Users/lukas/jiminny/app/app/Events/Activities/Crm
/Users/lukas/jiminny/app/app/Listeners/Playbooks
/Users/lukas/jiminny/app/app/Console/Commands/Crm
/Users/lukas/jiminny/app/app/Services/Crm
/Users/lukas/jiminny/app/app/Http/Controllers
/Users/lukas/jiminny/app/app/Console/Commands/Reports
/Users/lukas/jiminny/app/app/VO/Repository/OnDemandActivitySearch
/Users/lukas/jiminny/app/app/Listeners/Activities/Conferences/UserPilot
/Users/lukas/jiminny/app/app/Http/Controllers/Webhook
/Users/lukas/jiminny/app/resources/views/emails/reports...
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"Find in Files","depth":1,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"97 matches in 21 files","depth":1,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"File mask:","depth":1,"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXComboBox","text":"*.php","depth":1,"on_screen":true,"value":"*.php","role_description":"combo box","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"*.php","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Auto","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXTextField","text":"*.php","depth":2,"on_screen":true,"value":"*.php","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Filter Search Results","depth":1,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Pin Window","depth":1,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Search History","depth":1,"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"makeRequest","depth":2,"on_screen":true,"value":"makeRequest","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"New Line","depth":1,"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Match case","depth":1,"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Words","depth":1,"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Regex","depth":1,"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Replace History","depth":1,"bounds":{"left":0.0,"top":0.0,"width":0.015277778,"height":0.024444444},"on_screen":false,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"Replace","depth":2,"on_screen":false,"role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"New Line","depth":1,"bounds":{"left":0.0,"top":0.0,"width":0.015277778,"height":0.024444444},"on_screen":false,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Preserve case","depth":1,"bounds":{"left":0.0,"top":0.0,"width":0.015277778,"height":0.024444444},"on_screen":false,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"In Project","depth":2,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Module","depth":2,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Directory","depth":2,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Scope","depth":2,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"Module","depth":1,"bounds":{"left":0.0,"top":0.0,"width":0.20833333,"height":0.037777778},"on_screen":false,"role_description":"pop up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXComboBox","text":"/Users/lukas/jiminny/app/app/Services/Crm/Hubspot","depth":1,"bounds":{"left":0.0,"top":0.0,"width":0.4125,"height":0.037777778},"on_screen":false,"value":"/Users/lukas/jiminny/app/app/Services/Crm/Hubspot","role_description":"combo box","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"/Users/lukas/jiminny/app/app/Services/Crm/Hubspot","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/Users/lukas/jiminny/app/app/Exceptions","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/Users/lukas/jiminny/app/app/Listeners/Crm","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/Users/lukas/jiminny/app/app/Component/Queue/Job","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/Users/lukas/jiminny/app/app/Listeners/AutomatedReports/UserPilot","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/Users/lukas/jiminny/app/app/Events/Crm","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/Users/lukas/jiminny/app/app/Jobs/AutomatedReports","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/Users/lukas/jiminny/app/app/Listeners/Activities/Coaching/UserPilot","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/Users/lukas/jiminny/app/app/Listeners/Activities/ActivityProvider/UserPilot","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/Users/lukas/jiminny/app/app/Jobs/Activity/PushSummaryToCrm","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/Users/lukas/jiminny/app/app/Repositories/Crm","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/Users/lukas/jiminny/app/app/Jobs/Crm/Delete","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/Users/lukas/jiminny/app/app/Services/Kiosk/AutomatedReports","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/Users/lukas/jiminny/app/app/Http/Controllers/API/UserAutomatedReports","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/Users/lukas/jiminny/app/app/Services/Crm/Salesforce","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/Users/lukas/jiminny/app/app/Providers","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/Users/lukas/jiminny/app/app/Services/Crm/IntegrationApp","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/Users/lukas/jiminny/app/app/Events/Activities/Crm","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/Users/lukas/jiminny/app/app/Listeners/Playbooks","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/Users/lukas/jiminny/app/app/Console/Commands/Crm","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/Users/lukas/jiminny/app/app/Services/Crm","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/Users/lukas/jiminny/app/app/Http/Controllers","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/Users/lukas/jiminny/app/app/Console/Commands/Reports","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/Users/lukas/jiminny/app/app/VO/Repository/OnDemandActivitySearch","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/Users/lukas/jiminny/app/app/Listeners/Activities/Conferences/UserPilot","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/Users/lukas/jiminny/app/app/Http/Controllers/Webhook","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/Users/lukas/jiminny/app/resources/views/emails/reports","depth":6,"on_screen":false,"role_description":"text"}]...
|
-1563318650401350501
|
-882314081566108285
|
click
|
accessibility
|
NULL
|
Find in Files
97 matches in 21 files
File mask:
*. Find in Files
97 matches in 21 files
File mask:
*.php
*.php
Auto
*.php
Filter Search Results
Pin Window
Search History
makeRequest
New Line
Match case
Words
Regex
Replace History
Replace
New Line
Preserve case
In Project
Module
Directory
Scope
Module
/Users/lukas/jiminny/app/app/Services/Crm/Hubspot
/Users/lukas/jiminny/app/app/Services/Crm/Hubspot
/Users/lukas/jiminny/app/app/Exceptions
/Users/lukas/jiminny/app/app/Listeners/Crm
/Users/lukas/jiminny/app/app/Component/Queue/Job
/Users/lukas/jiminny/app/app/Listeners/AutomatedReports/UserPilot
/Users/lukas/jiminny/app/app/Events/Crm
/Users/lukas/jiminny/app/app/Jobs/AutomatedReports
/Users/lukas/jiminny/app/app/Listeners/Activities/Coaching/UserPilot
/Users/lukas/jiminny/app/app/Listeners/Activities/ActivityProvider/UserPilot
/Users/lukas/jiminny/app/app/Jobs/Activity/PushSummaryToCrm
/Users/lukas/jiminny/app/app/Repositories/Crm
/Users/lukas/jiminny/app/app/Jobs/Crm/Delete
/Users/lukas/jiminny/app/app/Services/Kiosk/AutomatedReports
/Users/lukas/jiminny/app/app/Http/Controllers/API/UserAutomatedReports
/Users/lukas/jiminny/app/app/Services/Crm/Salesforce
/Users/lukas/jiminny/app/app/Providers
/Users/lukas/jiminny/app/app/Services/Crm/IntegrationApp
/Users/lukas/jiminny/app/app/Events/Activities/Crm
/Users/lukas/jiminny/app/app/Listeners/Playbooks
/Users/lukas/jiminny/app/app/Console/Commands/Crm
/Users/lukas/jiminny/app/app/Services/Crm
/Users/lukas/jiminny/app/app/Http/Controllers
/Users/lukas/jiminny/app/app/Console/Commands/Reports
/Users/lukas/jiminny/app/app/VO/Repository/OnDemandActivitySearch
/Users/lukas/jiminny/app/app/Listeners/Activities/Conferences/UserPilot
/Users/lukas/jiminny/app/app/Http/Controllers/Webhook
/Users/lukas/jiminny/app/resources/views/emails/reports...
|
2852
|
NULL
|
NULL
|
NULL
|
|
3067
|
120
|
43
|
2026-05-07T11:58:57.975141+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-07/1778 /Users/lukas/.screenpipe/data/data/2026-05-07/1778155137975_m2.jpg...
|
PhpStorm
|
faVsco.js – IntegrationApp/…/SyncCrmEntitiesTrait. faVsco.js – IntegrationApp/…/SyncCrmEntitiesTrait.php...
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
Analyzing…
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\IntegrationApp\ServiceTraits;
use Carbon\Carbon;
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\Exception\RequestException;
use Illuminate\Support\Str;
use Jiminny\Events\Activities\Crm\LeadConverted;
use Jiminny\Models\Contact;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\LayoutEntity;
use Jiminny\Models\Lead;
use Jiminny\Models\Opportunity;
use Jiminny\Models\Stage;
use Jiminny\Models\Team;
use Jiminny\Models\Account;
use Jiminny\Jobs\Crm\MatchActivitiesToNewOpportunity;
use Jiminny\Repositories\Crm\CrmEntityRepository;
use Jiminny\Repositories\Crm\FieldDataRepository;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Repositories\Crm\StageRepository;
use Jiminny\Services\Crm\IntegrationApp\Config\IntegrationConfigInterface as IntegrationConfig;
use Jiminny\Services\Crm\IntegrationApp\DTO;
use Jiminny\Services\Crm\IntegrationApp\DataClient;
use Jiminny\Services\Crm\OpportunitySyncStrategyResolver;
use Jiminny\Utils\CurrencyFormatter;
use Psr\Log\LoggerInterface;
/**
* This trait follows closely the contract SyncCrmEntitiesInterface
*/
trait SyncCrmEntitiesTrait
{
use ExternalMapsTrait;
private const int CHUNK_SIZE = 100;
public ?Team $team = null;
public ?Configuration $config;
public ?IntegrationConfig $editionConfig;
protected LoggerInterface $logger;
/**
* @var DataClient
*/
protected $client;
public function syncAllAccounts(): int
{
$count = 0;
foreach ($this->client->getAllAccounts() as $eachAccount) {
$this->importAccount($eachAccount);
$count++;
}
return $count;
}
public function syncAccounts(Carbon $since, ?Carbon $to = null): int
{
$count = 0;
$this->logger->info('[integration-app] Syncing accounts', [
'since' => $since,
'to' => $to,
'team_id' => $this->team?->getId(),
]);
$params = [
'since' => $since,
'to' => $to,
];
/** @var DTO\Account $eachAccount*/
foreach ($this->client->getFilteredAccounts($params) as $eachAccount) {
$this->importAccount($eachAccount);
$count++;
}
$this->logger->info('[integration-app] Syncing accounts finished successfully', [
'since' => $since,
'to' => $to,
'team_id' => $this->team?->getId(),
]);
return $count;
}
public function syncAccount(string $crmId): ?Account
{
try {
$accountDto = $this->client->getSingleAccount($crmId);
if ($accountDto === null) {
return null;
}
return $this->importAccount($accountDto);
} catch (RequestException) {
return null;
}
}
private function importAccount(DTO\Account $accountDto): Account
{
/** @var CrmEntityRepository $crmEntityRepo */
$crmEntityRepo = app(CrmEntityRepository::class);
$data = [
'crm_provider_id' => $accountDto->externalId,
'user_id' => $this->findMappedUserId($accountDto->ownerId),
'owner_id' => $accountDto->ownerId,
'name' => mb_substr($accountDto->name, 0, 191),
'phone' => $accountDto->phone !== null ? mb_substr($accountDto->phone, 0, 25) : null,
'industry' => $accountDto->industry !== null ? mb_substr($accountDto->industry, 0, 191) : null,
'domain' => $accountDto->websiteUrl !== null ? mb_substr($accountDto->websiteUrl, 0, 191) : null,
'country_code' => $accountDto->countryCode,
'remotely_created_at' => $accountDto->createdAt,
];
$this->logger->info('[integration-app] Importing account', [
'crm_provider_id' => $accountDto->externalId,
'team_id' => $this->team?->getId(),
]);
$account = $crmEntityRepo->importAccount($this->getConfiguration(), $data);
$this->mapExternalAccount($account);
return $account;
}
// Sync multiple records.
public function syncAllContacts(): int
{
$count = 0;
foreach ($this->client->getAllContacts() as $eachContact) {
// import contacts here
$this->importContact(contactDto: $eachContact);
$count++;
}
return $count;
}
public function syncContacts(Carbon $since, ?Carbon $to = null): int
{
$count = 0;
$this->logger->info('[integration-app] Syncing contacts', [
'since' => $since,
'to' => $to,
'team_id' => $this->team?->getId(),
]);
$params = [
'since' => $since,
'to' => $to,
];
foreach ($this->client->getFilteredContacts($params) as $eachContact) {
$this->importContact($eachContact);
$count++;
}
$this->logger->info('[integration-app] Syncing contacts finished successfully', [
'since' => $since,
'to' => $to,
'team_id' => $this->team?->getId(),
]);
return $count;
}
// Sync single records.
public function syncContact(string $crmId): ?Contact
{
try {
$contactRecord = $this->client->getSingleContact($crmId);
if ($contactRecord === null) {
return null;
}
return $this->importContact($contactRecord);
} catch (RequestException) {
return null;
}
}
private function importContact(DTO\Contact $contactDto): ?Contact
{
$createInternalAccount = false;
/** @var CrmEntityRepository $crmEntityRepo */
$crmEntityRepo = app(CrmEntityRepository::class);
$accountId = $this->findMappedAccountId(
pivotEntityId: $contactDto->externalId,
externalAccountId: $contactDto->accountId,
);
$userId = $this->findMappedUserId($contactDto->ownerId);
if ($accountId === null) {
$this->logger->info('[integration-app] Importing contact, but related account cannot be found', [
'crm_provider_id' => $contactDto->externalId,
'raw_account_id' => $contactDto->accountId,
'name' => $contactDto->fullName,
'user_id' => $userId,
]);
$createInternalAccount = true;
}
$data = [
'user_id' => $userId,
'account_id' => $accountId,
'crm_provider_id' => $contactDto->externalId,
'owner_id' => $contactDto->ownerId,
'name' => $contactDto->fullName !== null ? mb_substr($contactDto->fullName, 0, 100) : null,
'title' => $contactDto->title !== null ? mb_substr($contactDto->title, 0, 100) : null,
'email' => $contactDto->primaryEmail !== null ? mb_substr($contactDto->primaryEmail, 0, 191) : null,
'phone' => $contactDto->phone !== null ? mb_substr($contactDto->phone, 0, 25) : null,
'mobile_phone' => $contactDto->mobilePhone !== null ? mb_substr($contactDto->mobilePhone, 0, 25) : null,
'country_code' => $contactDto->countryCode !== null ? mb_substr($contactDto->countryCode, 0, 2) : null,
'remotely_created_at' => $contactDto->createdAt,
'photo_path' => '',
];
$this->logger->info('[integration-app] Importing contact', [
'crm_provider_id' => $contactDto->externalId,
'team_id' => $this->team?->getId(),
]);
$contact = $crmEntityRepo->importContact($this->getConfiguration(), $data);
$this->mapExternalContact($contact);
if ($createInternalAccount) {
$this->createInternalAccountFromContact($contact)->getId();
}
return $contact;
}
/**
* @param bool $matchFromOtherCrm - This parameter is intended to be manually used. It will help with
* matching older opportunities if the team is transitioning from one CRM provider to another.
*/
public function syncAllOpportunities(bool $matchFromOtherCrm = false): int
{
$count = 0;
foreach ($this->client->getAllOpportunities() as $eachDeal) {
$this->upsertOpportunity($eachDeal, $matchFromOtherCrm);
$count++;
}
return $count;
}
public function syncOpportunities(array $parameters, ?string $strategy = null): int
{
$parameters['strategy'] = $strategy ?? OpportunitySyncStrategyResolver::LAST_MODIFIED_SYNC_OPPORTUNITY_STRATEGY;
$count = 0;
$this->logger->info('[integration-app] Syncing opportunities', [
'parameters' => $parameters,
'team_id' => $this->team?->getId(),
]);
/** @var DTO\Opportunity[] $pageResultData */
foreach ($this->client->getFilteredOpportunities($parameters) as $pageResultData) {
$externalAccounts = [];
$externalContacts = [];
foreach ($pageResultData as $eachRecord) {
$externalAccounts[] = $eachRecord->accountId ?? null;
$externalContacts[] = $eachRecord->contactId ?? null;
}
// Import missing contacts and account as early as possible
$missingContacts = $this->identifyMissingContacts($externalContacts);
if (! empty($missingContacts)) {
$this->batchSyncContacts($missingContacts);
}
$missingAccounts = $this->identifyMissingAccounts($externalAccounts);
if (! empty($missingAccounts)) {
$this->batchSyncAccounts($missingAccounts);
}
foreach ($pageResultData as $eachRecord) {
$this->upsertOpportunity($eachRecord);
$count++;
}
}
$this->logger->info('[integration-app] Syncing opportunities finished successfully', [
'parameters' => $parameters,
'team_id' => $this->team?->getId(),
]);
return $count;
}
public function syncOpportunity(string $crmId): ?Opportunity
{
try {
$opportunityRecord = $this->client->getSingleOpportunity($crmId);
if ($opportunityRecord === null) {
return null;
}
return $this->upsertOpportunity($opportunityRecord);
} catch (RequestException) {
return null;
}
}
public function syncAllLeads(): int
{
if (isset($this->config->getSettings()['lead_sync_disabled'])) {
$this->logger->info('[integration-app] Syncing leads disabled for the client', [
'team_id' => $this->team?->getId(),
]);
return 0;
}
$count = 0;
foreach ($this->client->getAllLeads() as $eachLead) {
$this->importLead($eachLead);
$count++;
}
return $count;
}
public function syncLeads(Carbon $since, ?Carbon $to = null, ?string $crmProfileId = null): int
{
if (isset($this->config->getSettings()['lead_sync_disabled'])) {
$this->logger->info('[integration-app] Syncing leads disabled for the client', [
'team_id' => $this->team?->getId(),
'since' => $since,
'to' => $to,
'crm_profile_id' => $crmProfileId,
]);
return 0;
}
$count = 0;
$this->logger->info('[integration-app] Syncing leads', [
'since' => $since,
'to' => $to,
'crm_profile_id' => $crmProfileId,
'team_id' => $this->team?->getId(),
]);
$filterData = [
'since' => $since,
'to' => $to,
'crm_profile_id' => $crmProfileId,
'converted' => 'both',
];
foreach ($this->client->getFilteredLeads($filterData) as $eachLead) {
$this->importLead($eachLead);
$count++;
}
$this->logger->info('[integration-app] Syncing leads finished successfully', [
'since' => $since,
'to' => $to,
'team_id' => $this->team?->getId(),
]);
return $count;
}
public function syncLead(string $crmId): ?Lead
{
if (isset($this->config->getSettings()['lead_sync_disabled'])) {
$this->logger->info('[integration-app] Syncing leads disabled for the client', [
'team_id' => $this->team?->getId(),
'crm_id' => $crmId,
]);
return null;
}
try {
$leadRecord = $this->client->getSingleAndConvertLead($crmId);
if ($leadRecord === null) {
return null;
}
return $this->importLead($leadRecord);
} catch (RequestException) {
return null;
}
}
private function importLead(DTO\Lead $leadDto): ?Lead
{
/** @var CrmEntityRepository $crmEntityRepo */
$crmEntityRepo = app(CrmEntityRepository::class);
$userId = $this->findMappedUserId($leadDto->ownerId);
$stage = null;
if ($this->editionConfig->supportsStages()) {
// Get the current stage.
$stage = $crmEntityRepo->getStageForName(
configuration: $this->config,
name: $leadDto->status,
type: Stage::TYPE_LEAD
);
}
if ($stage === null && ! empty($leadDto->status)) {
// Try to sync and import the lead stage by name only
$stage = $this->syncStageByNameOnly($this->config, $leadDto->status, Stage::TYPE_LEAD);
}
$stageId = $stage?->id;
$leadData = [
'team_id' => $this->team->getId(),
'crm_configuration_id' => $this->config->getId(),
'crm_provider_id' => $leadDto->externalId,
'name' => $leadDto->fullName,
'company' => $leadDto->companyName,
'owner_id' => $leadDto->ownerId,
'user_id' => $userId,
'stage_id' => $stageId,
'email' => $leadDto->primaryEmail,
'phone' => $leadDto->primaryPhone,
'mobile_phone' => $leadDto->secondaryPhone,
'title' => $leadDto->jobTitle,
'remotely_created_at' => $leadDto->createdAt,
];
$convertedLeadData = $this->processConvertedLead($crmEntityRepo, $leadDto);
$leadData = array_merge($leadData, $convertedLeadData);
$this->logger->info('[integration-app] Importing lead', [
'crm_provider_id' => $leadDto->externalId,
'name' => $leadDto->primaryEmail,
'team_id' => $this->team?->getId(),
]);
$lead = $crmEntityRepo->importLead($this->config, $leadData);
$this->dispatchLeadConvertedEvent($lead);
return $lead;
}
private function processConvertedLead(CrmEntityRepository $crmEntityRepo, DTO\Lead $leadDto): array
{
if (! $leadDto->isConverted()) {
return [];
}
$leadData = [
'converted_at' => $leadDto->getConvertedAt(),
];
$this->decorateWithConvertedContact($crmEntityRepo, $leadDto, $leadData);
$this->decorateWithConvertedAccount($crmEntityRepo, $leadDto, $leadData);
$this->decorateWithConvertedOpportunity($crmEntityRepo, $leadDto, $leadData);
return $leadData;
}
private function dispatchLeadConvertedEvent(Lead $lead): void
{
if ($lead->wasChanged('converted_at') && $lead->getConvertedAt() !== null) {
event(new LeadConverted($lead));
}
}
private function decorateWithConvertedContact(
CrmEntityRepository $crmEntityRepo,
DTO\Lead $leadDto,
array &$leadData
): void {
if ($leadDto->getConvertedContactId() !== null) {
$convertedContact = $crmEntityRepo->findContactByExternalId(
$this->config,
$leadDto->getConvertedContactId()
);
if ($convertedContact === null) {
try {
$convertedContact = $this->syncContact($leadDto->getConvertedContactId());
} catch (\Exception $exception) {
$this->logger->error('[integration-app] Error syncing converted contact', [
'lead_id' => $leadDto->getExternalId(),
'crm_provider_id' => $leadDto->getConvertedContactId(),
'error' => $exception->getMessage(),
]);
}
}
$leadData['converted_contact_id'] = $convertedContact?->getId();
}
}
private function decorateWithConvertedAccount(
CrmEntityRepository $crmEntityRepo,
DTO\Lead $leadDto,
array &$leadData
): void {
if ($leadDto->getConvertedAccountId() !== null) {
$convertedAccount = $crmEntityRepo->findAccountByExternalId(
$this->config,
$leadDto->getConvertedAccountId()
);
if ($convertedAccount === null) {
try {
$convertedAccount = $this->syncAccount($leadDto->getConvertedAccountId());
} catch (\Exception $exception) {
$this->logger->error('[integration-app] Error syncing converted account', [
'lead_id' => $leadDto->getExternalId(),
'crm_provider_id' => $leadDto->getConvertedAccountId(),
'error' => $exception->getMessage(),
]);
}
}
$leadData['converted_account_id'] = $convertedAccount?->getId();
}
}
private function decorateWithConvertedOpportunity(
CrmEntityRepository $crmEntityRepo,
DTO\Lead $leadDto,
array &$leadData
): void {
if ($leadDto->getConvertedOpportunityId() !== null) {
$convertedOpportunity = $crmEntityRepo->findOpportunityByExternalId(
$this->config,
$leadDto->getConvertedOpportunityId()
);
if ($convertedOpportunity === null) {
try {
$convertedOpportunity = $this->syncOpportunity($leadDto->getConvertedOpportunityId());
} catch (\Exception $exception) {
$this->logger->error('[integration-app] Error syncing converted opportunity', [
'lead_id' => $leadDto->getExternalId(),
'crm_provider_id' => $leadDto->getConvertedOpportunityId(),
'error' => $exception->getMessage(),
]);
}
}
$leadData['converted_opportunity_id'] = $convertedOpportunity?->getId();
}
}
/**
* @throws GuzzleException
*/
public function importStages(?array $types = null, ?string $missingStageName = null): ?Stage
{
if (! $this->editionConfig->supportsStages()) {
return null;
}
$missingStage = null;
$stagesCollection = $this->client->getAllDealsStages();
foreach ($stagesCollection as $eachStage) {
$stage = $this->importStage($eachStage);
if ($stage->getName() === $missingStageName) {
$missingStage = $stage;
}
}
return $missingStage;
}
private function importStage(DTO\EntityStage $stageDto): Stage
{
/** @var CrmEntityRepository $crmEntityRepo */
$crmEntityRepo = app(CrmEntityRepository::class);
$objectType = $stageDto->type ?? Stage::TYPE_OPPORTUNITY;
$stageData = [
'crm_provider_id' => $stageDto->externalId,
'name' => mb_strimwidth($stageDto->apiName ?? $stageDto->name, 0, 50),
'label' => mb_strimwidth($stageDto->masterLabel ?? $stageDto->name, 0, 191),
'sequence' => $stageDto->sortOrder ?? 0,
'probability' => $stageDto->defaultProbability ?? null,
'is_selectable' => $stageDto->isActive ?? 0,
'type' => $objectType,
];
$this->logger->info('[integration-app] Importing stage', [
'crm_provider_id' => $stageDto->externalId,
'name' => $stageDto->name,
'team_id' => $this->team?->getId(),
]);
$stage = $crmEntityRepo->importStage($this->config, $objectType, $stageData);
// Include newly imported stages to the map
$this->mapExternalStage($stage);
return $stage;
}
/**
* Attach a stage to a default business process.
* This method is used only in Zoho implementation
* where both supportsPipelines and supportsPipelines are false
*/
public function syncBusinessProcessStages(int $stageId): void
{
/** @var StageRepository $stageRepository */
$stageRepository = app(StageRepository::class);
$processName = 'DefaultOpportunityProcess';
$data = [
'team_id' => $this->team->getId(),
'name' => $processName,
'type' => Stage::TYPE_OPPORTUNITY,
'is_selectable' => true,
];
$businessProcess = $stageRepository->findOrCreateBusinessProcess(
$this->config,
$processName,
$data
);
$businessProcess->stages()->attach($stageId);
}
/**
* bool $matchFromOtherCrm
* When inserting a deal match try to match it to an existing from other CRM within the same team.
* - This parameter is intended to be manually used only. It will help with
* matching older opportunities if the team is transitioning from one CRM provider to another.
*/
private function upsertOpportunity(DTO\Opportunity $opportunityDto, bool $matchFromOtherCrm = false): ?Opportunity
{
$this->logger->info('[integration-app] Importing opportunity', [
'crm_provider_id' => $opportunityDto->externalId,
'team_id' => $this->team->getId(),
]);
if ($this->config === null) {
$this->logger->warning('[integration-app] Opportunity missing config');
return null;
}
$stageId = $this->findOpportunityStageId(
externalStageId: $opportunityDto->stageId,
stageName: $opportunityDto->stageName
);
// temporary detect memory usage
$this->logger->info('[integration-app] Stage ID', [
'memory_usage' => memory_get_usage(),
'memory_real_usage' => memory_get_usage(true),
'crm_provider_id' => $opportunityDto->externalId,
'stage_id' => $stageId,
]);
$accountId = $this->findAccountId(
pivotEntityId: $opportunityDto->externalId,
externalAccountId: $opportunityDto->accountId,
externalContactId: $opportunityDto->contactId,
);
$this->logger->info('[integration-app] Account ID', [
'memory_usage' => memory_get_usage(),
'memory_real_usage' => memory_get_usage(true),
'crm_provider_id' => $opportunityDto->externalId,
'account_id' => $accountId,
]);
if ($stageId === null || $accountId === null) {
$this->logger->warning('[integration-app] Opportunity missing data', [
'stageId' => $stageId,
'accountId' => $accountId,
'externalId' => $opportunityDto->externalId,
]);
return null;
}
$userId = $this->findMappedUserId(externalUserId: $opportunityDto->ownerId);
$data = [
'crm_provider_id' => $opportunityDto->externalId,
'team_id' => $this->team->getId(),
'account_id' => $accountId,
'user_id' => $userId,
'owner_id' => $opportunityDto->ownerId,
'name' => mb_strimwidth($opportunityDto->name, 0, 128),
'value' => $opportunityDto->amount,
'currency_code' => CurrencyFormatter::formatCode($this->getCurrencyIso($opportunityDto)),
'close_date' => $opportunityDto->closeDate,
'is_closed' => $opportunityDto->closed,
'is_won' => $opportunityDto->won,
'stage_id' => $stageId,
'record_type_id' => null,
'remotely_created_at' => $opportunityDto->createdAt,
'probability' => $opportunityDto->probability,
];
/** @var CrmEntityRepository $crmEntityRepo */
$crmEntityRepo = app(CrmEntityRepository::class);
$opportunity = $crmEntityRepo->importOpportunity(
$this->config,
$data,
$matchFromOtherCrm,
$opportunityDto->name,
);
// Import external fields into crm_field_data if present
$crmFields = $this->getOpportunitySyncableFields();
$this->importOpportunityFieldData($opportunityDto, $crmFields, $opportunity->getId());
if ($opportunityDto->deleted === true) {
$opportunity->delete();
return $opportunity;
}
if ($opportunity->wasRecentlyCreated) {
MatchActivitiesToNewOpportunity::dispatch($opportunity->getId());
}
return $opportunity;
}
private function findOpportunityStageId(?string $externalStageId, ?string $stageName): ?int
{
$stageId = null;
if ($this->editionConfig->supportsStages()) {
$stageId = $this->findMappedStageId(externalStageId: $externalStageId, type: Stage::TYPE_OPPORTUNITY);
if ($stageId === null) {
$stageId = $this->importStages(types: [Stage::TYPE_OPPORTUNITY], missingStageName: $stageName)?->id;
}
}
if ($stageId === null && $stageName !== null) {
$stageId = $this->syncStageByNameOnly(
configuration: $this->config,
stageName: $stageName,
type: Stage::TYPE_OPPORTUNITY
)?->id;
}
return $stageId;
}
private function importOpportunityFieldData(
DTO\Opportunity $opportunityDto,
array $crmFields,
int $opportunityId
): void {
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
/** @var FieldDataRepository $fieldDataRepository */
$fieldDataRepository = app(FieldDataRepository::class);
foreach ($crmFields as $crmField) {
if (! property_exists($opportunityDto, $crmField)) {
continue;
}
if ($opportunityDto->{$crmField} === null) {
continue;
}
$field = $fieldRepository->findFieldByCrmIdAndObjectType(
$this->config,
$crmField,
Field::OBJECT_OPPORTUNITY
);
if (! $field instanceof Field) {
$this->logger->info('Field not found', [
'field' => $crmField,
'config' => $this->config->getId(),
]);
continue;
}
$entities = $field->getEntities();
if ($entities->isEmpty()) {
$this->logger->info('Field has no entities', [
'field' => $crmField,
'config' => $this->config->getId(),
]);
continue;
}
if ($entities->count() > 1) {
$this->logger->info('Field has multiple entities', [
'field' => $crmField,
'config' => $this->config->getId(),
]);
continue;
}
/** @var LayoutEntity|null $entity */
$entity = $entities->first();
if (! $entity instanceof LayoutEntity) {
continue;
}
$value = (string) $opportunityDto->{$crmField};
$fieldDataRepository->updateOrCreateFieldData(
$entity,
$opportunityId,
$value,
);
}
}
private function getCurrencyIso(DTO\Opportunity $opportunityDto): ?string
{
if ($opportunityDto->currencyIso !== null) {
return $opportunityDto->currencyIso;
}
// Fallback to billing currency
return $this->config->getDefaultCurrency();
}
/**
* Some CRM providers do not support listing all stages.
* Additionally, they may not even supply us with a stage ID when the stage is supplied as a property of the deal.
* In that case, we will usually have only a stage name.
* In order to import such stages only once, we will slugify them and produce "external ID" on our own.
*/
private function syncStageByNameOnly(Configuration $configuration, string $stageName, ?string $type = null): ?Stage
{
// @TEMP For testing purposes only!!!
// Revert when we find suitable way to fetch the stage
/** @var CrmEntityRepository $crmEntityRepo */
$crmEntityRepo = app(CrmEntityRepository::class);
$stage = $crmEntityRepo->getStageForName($configuration, $stageName, $type);
if ($stage !== null) {
return $stage;
}
// if there is other legitimate way to fetch the stage skip.
if ($this->editionConfig->supportsPipelines() ||
$this->editionConfig->supportsStages()
) {
return null;
}
/** @var CrmEntityRepository $crmEntityRepo */
$crmEntityRepo = app(CrmEntityRepository::class);
$stage = $crmEntityRepo->getStageForName($configuration, $stageName, $type);
// Create the stage if it does not exist already
if ($stage === null) {
$stageDto = new DTO\EntityStage();
$stageDto->externalId = $stageName;
$stageDto->masterLabel = Str::slug($stageName);
$stageDto->name = $stageName;
$stageDto->type = $type;
$stage = $this->importStage($stageDto);
if ($type === Stage::TYPE_OPPORTUNITY) {
$this->syncBusinessProcessStages($stage->getId());
}
}
return $stage;
}
private function findAccountId(
string $pivotEntityId,
?string $externalAccountId = null,
?string $externalContactId = null,
bool $skipAccountSync = false,
): ?int {
$accountId = $this->findMappedAccountId(
pivotEntityId: $pivotEntityId,
externalAccountId: $externalAccountId,
skipAccountSync: $skipAccountSync,
);
if ($accountId !== null) {
return $accountId;
}
/**
* The deal probably does not have an Account assigned.
* In order to not break the existing import, we will try to find a contact
* and create an Account with the same data.
*/
if (! empty($externalContactId)) {
// In rare cases the contact's external id matches our account id, whe :(
$this->logger->info('[integration-app] fallback Account', ['contact_id' => $externalContactId]);
$accountId = $this->findMappedAccountId(
pivotEntityId: $pivotEntityId,
externalAccountId: $externalContactId,
skipAccountSync: true,
);
if ($accountId !== null) {
return $accountId;
}
$this->logger->info('[integration-app] create Account from Contact', ['contact_id' => $externalContactId]);
$crmEntityRepo = app(CrmEntityRepository::class);
$contact = $crmEntityRepo->findContactByExternalId($this->config, $externalContactId);
if ($contact !== null) {
return $this->createInternalAccountFromContact($contact)->getId();
}
}
return null;
}
private function createInternalAccountFromContact(Contact $contact): Account
{
$this->logger->info('[integration-app] Create internal account from contact', [
'team_id' => $this->team?->getId(),
'contact_id' => $contact->getId(),
'crm_provider_id' => $contact->getCrmProviderId(),
]);
$data = [
'crm_configuration_id' => $this->config->getId(),
'team_id' => $this->config->getTeamId(),
'crm_provider_id' => $contact->getCrmProviderId(),
'user_id' => $contact->getUserId(),
'owner_id' => $contact->getOwnerId(),
'name' => $contact->getName(),
'phone' => $contact->getPhone(),
'country_code' => $contact->getCountryCode(),
'remotely_created_at' => $contact->getRemotelyCreatedAt(),
'is_internal' => 1,
];
/** @var CrmEntityRepository $crmEntityRepo */
$crmEntityRepo = app(CrmEntityRepository::class);
$account = $crmEntityRepo->importAccount($this->config, $data);
if ($contact->account_id === null) {
$contact->account_id = $account->getId();
$contact->save();
}
$this->mapExternalAccount($account);
return $account;
}
private function batchSyncContacts(array $externalContactIds): void
{
$this->logger->info('[integration-app] Syncing batch contacts', [
'batch_contacts' => implode(',', $externalContactIds),
'team_id' => $this->team?->getId(),
]);
/** IntegrationApp allows up to 100 IDs passed as a batch. */
$chunkedContacts = array_chunk($externalContactIds, self::CHUNK_SIZE);
foreach ($chunkedContacts as $contactGroup) {
/** @var DTO\Contact[] $pageResultData */
foreach ($this->client->getBatchContactsById($contactGroup) as $pageResultData) {
$externalAccounts = [];
foreach ($pageResultData as $eachRecord) {
$externalAccounts[] = $eachRecord->accountId ?? null;
}
$missingAccounts = $this->identifyMissingAccounts($externalAccounts);
if (! empty($missingAccounts)) {
$this->batchSyncAccounts($missingAccounts);
}
foreach ($pageResultData as $eachRecord) {
$this->importContact($eachRecord);
}
}
}
}
private function batchSyncAccounts(array $externalAccountIds): void
{
$this->logger->info('[integration-app] Syncing batch accounts', [
'batch_contacts' => implode(',', $externalAccountIds),
'team_id' => $this->team?->getId(),
]);
/** IntegrationApp allows up to 100 IDs passed as a batch. */
$chunkedAccounts = array_chunk($externalAccountIds, self::CHUNK_SIZE);
foreach ($chunkedAccounts as $accountGroup) {
/** @var DTO\Account[] $pageResultData */
foreach ($this->client->getBatchAccountsById($accountGroup) as $pageResultData) {
foreach ($pageResultData as $eachRecord) {
$this->importAccount($eachRecord);
}
}
}
}
/**
* Identify all contacts Ids, that are not found in our database.
* Scoped to the current batch so memory and query cost scale with batch size,
* not with tenant size.
*
* @param array<?string> $contacts
*
* @return list<string>
*/
private function identifyMissingContacts(array $contacts): array
{
$wanted = array_values(array_unique(array_filter($contacts)));
if ($wanted === []) {
return [];
}
/** @var CrmEntityRepository $crmEntityRepo */
$crmEntityRepo = app(CrmEntityRepository::class);
$existing = $crmEntityRepo->getExistingContactCrmIds($this->config, $wanted);
return array_values(array_diff($wanted, $existing));
}
/**
* Identify all account Ids, that are not found in our database.
* Scoped to the current batch so memory and query cost scale with batch size,
* not with tenant size.
*
* @param array<?string> $accounts
*
* @return list<string>
*/
private function identifyMissingAccounts(array $accounts): array
{
$wanted = array_values(array_unique(array_filter($accounts)));
if ($wanted === []) {
return [];
}
/** @var CrmEntityRepository $crmEntityRepo */
$crmEntityRepo = app(CrmEntityRepository::class);
$existing = $crmEntityRepo->getExistingAccountCrmIds($this->config, $wanted);
return array_values(array_diff($wanted, $existing));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode, folder
.windsurf
app, sources root
Actions
Component
Acl
ActionItems, folder
Activity, folder
ActivityAnalytics
ActivitySearch
AiActivityType, folder
AiAutomation, folder
AiCallScoring, folder
AskAnything
Dtos
Events
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi
AWS
BillingManagement
Cache
CoachingFeedback
Country, folder
CustomerApi, folder
Database, folder
Datadog, folder
DateTime, folder
DealInsights, folder
DealRisks
ElasticSearch
Eloquent
Encoding
Encryption
ES
Faker
FeatureFlags
FFMpeg
FileSystem
Gecko
Gong
GuzzleHttp
KeyPoints
Kiosk
LanguageDetection
LiveFeed
Locks
Math
MediaPipeline
MeetingBot
MobileSettings, folder
Model, folder
Notification, folder
Nudge
ParagraphBreaker
ParticipantSpeech
PartitionedCookie
PlaybackPage
Playlist
Prophet
ProphetAi, folder
ProsperWorks
Queue
Job
RateLimitAware.php, abstract class
RateLimitAwareWrapper.php, class
BotsQueueConstants.php
Constants.php
ProcessingQueueConstants.php
Router, folder
Saml2
SCIM
Seeder
Sentry
Serializer
Settings
Sidekick
Slack
TeamInsights, folder
TimeMemoryMapper, folder
Transcription
TranscriptionSummary
Twilio
Uploader
UrlGenerator
Utility
Exceptions
Service
BaseRateLimiter.php, class
EfficientJsonParser.php, class
ProviderRateLimiter.php, class
RateLimiterInstance.php, class
Uuid
Waveform
Webhooks
Workflow
Configuration
Console, folder
Commands
Activities
Analytics
Calendars
Crm
Hubspot
IntegrationApp
Traits
AddLayoutEntities.php, class
AutologDelayedCommand.php, class
BullhornCommandAbstract.php, abstract class
BullhornPingCommand.php, class
BullhornSearchCommand.php, class
BullhornSessionCommand.php, class
CheckActivityLoggableCommand.php, final class
CleanDuplicateFieldDataCommand.php, class
FullSyncOpportunityCommand.php, class
LogActivitiesCommand.php, final class
ManageSyncStrategyCommand.php, class
MatchCrmObjectsCommand.php, class
MatchOpportunityActivitiesCommand.php, class
MigrateProvider.php, class
ProcessHubspotObjectsSyncBatches.php, class
PurgeDeletedOpportunitiesCommand.php, class
ResetGovernorLimits.php, class
SendNotLogged.php, class
SetupActivityTypeForFollowUp.php, final class
SetupCloseCrm.php, class
SetupCopperCrm.php, class
SetupCrmCommand.php, abstract class
SetupLayouts.php, class
SyncAccount.php, class
SyncContact.php, class
SyncFieldMetadata.php, class
SyncHubspotActiveDeals.php, class
SyncHubspotObjects.php, class
SyncLead.php, class
SyncObjects.php, class
SyncOpportunitiesMissingFieldDataCommand.php, class
SyncOpportunity.php, class
SyncProfileMetadata.php, class
SyncTeamMetadata.php, class
UpdateOpportunitySpecifications.php, class
DealInsights
Dev
AddRateLimitCommand.php, class
FixHubSpotTokens.php, class
FixMissMatchedCrmActivitiesCommand.php, final class
ImportCallsCommand.php, class
MonitorSocialAccountsState.php, class
Dialers
DTOs
Elasticsearch
EngagementStats
GeckoExport
Livestream
Mailboxes
Migrate...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.034242023,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: master","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8081782,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"bounds":{"left":0.8234708,"top":0.019952115,"width":0.09208777,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"","depth":4,"bounds":{"left":0.52859044,"top":0.0726257,"width":0.45977393,"height":0.9066241},"on_screen":true,"value":"","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Analyzing…","depth":4,"bounds":{"left":0.5053192,"top":0.17478053,"width":0.019946808,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\IntegrationApp\\ServiceTraits;\n\nuse Carbon\\Carbon;\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse GuzzleHttp\\Exception\\RequestException;\nuse Illuminate\\Support\\Str;\nuse Jiminny\\Events\\Activities\\Crm\\LeadConverted;\nuse Jiminny\\Models\\Contact;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\LayoutEntity;\nuse Jiminny\\Models\\Lead;\nuse Jiminny\\Models\\Opportunity;\nuse Jiminny\\Models\\Stage;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Models\\Account;\nuse Jiminny\\Jobs\\Crm\\MatchActivitiesToNewOpportunity;\nuse Jiminny\\Repositories\\Crm\\CrmEntityRepository;\nuse Jiminny\\Repositories\\Crm\\FieldDataRepository;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Repositories\\Crm\\StageRepository;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\Config\\IntegrationConfigInterface as IntegrationConfig;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DataClient;\nuse Jiminny\\Services\\Crm\\OpportunitySyncStrategyResolver;\nuse Jiminny\\Utils\\CurrencyFormatter;\nuse Psr\\Log\\LoggerInterface;\n\n/**\n * This trait follows closely the contract SyncCrmEntitiesInterface\n */\ntrait SyncCrmEntitiesTrait\n{\n use ExternalMapsTrait;\n\n private const int CHUNK_SIZE = 100;\n\n public ?Team $team = null;\n public ?Configuration $config;\n public ?IntegrationConfig $editionConfig;\n protected LoggerInterface $logger;\n /**\n * @var DataClient\n */\n protected $client;\n\n public function syncAllAccounts(): int\n {\n $count = 0;\n foreach ($this->client->getAllAccounts() as $eachAccount) {\n $this->importAccount($eachAccount);\n $count++;\n }\n\n return $count;\n }\n\n public function syncAccounts(Carbon $since, ?Carbon $to = null): int\n {\n $count = 0;\n $this->logger->info('[integration-app] Syncing accounts', [\n 'since' => $since,\n 'to' => $to,\n 'team_id' => $this->team?->getId(),\n ]);\n\n $params = [\n 'since' => $since,\n 'to' => $to,\n ];\n\n /** @var DTO\\Account $eachAccount*/\n foreach ($this->client->getFilteredAccounts($params) as $eachAccount) {\n $this->importAccount($eachAccount);\n $count++;\n }\n\n $this->logger->info('[integration-app] Syncing accounts finished successfully', [\n 'since' => $since,\n 'to' => $to,\n 'team_id' => $this->team?->getId(),\n ]);\n\n return $count;\n }\n\n public function syncAccount(string $crmId): ?Account\n {\n try {\n $accountDto = $this->client->getSingleAccount($crmId);\n if ($accountDto === null) {\n return null;\n }\n\n return $this->importAccount($accountDto);\n } catch (RequestException) {\n return null;\n }\n }\n\n private function importAccount(DTO\\Account $accountDto): Account\n {\n /** @var CrmEntityRepository $crmEntityRepo */\n $crmEntityRepo = app(CrmEntityRepository::class);\n $data = [\n 'crm_provider_id' => $accountDto->externalId,\n 'user_id' => $this->findMappedUserId($accountDto->ownerId),\n 'owner_id' => $accountDto->ownerId,\n 'name' => mb_substr($accountDto->name, 0, 191),\n 'phone' => $accountDto->phone !== null ? mb_substr($accountDto->phone, 0, 25) : null,\n 'industry' => $accountDto->industry !== null ? mb_substr($accountDto->industry, 0, 191) : null,\n 'domain' => $accountDto->websiteUrl !== null ? mb_substr($accountDto->websiteUrl, 0, 191) : null,\n 'country_code' => $accountDto->countryCode,\n 'remotely_created_at' => $accountDto->createdAt,\n ];\n\n $this->logger->info('[integration-app] Importing account', [\n 'crm_provider_id' => $accountDto->externalId,\n 'team_id' => $this->team?->getId(),\n ]);\n\n $account = $crmEntityRepo->importAccount($this->getConfiguration(), $data);\n $this->mapExternalAccount($account);\n\n return $account;\n }\n\n // Sync multiple records.\n public function syncAllContacts(): int\n {\n $count = 0;\n foreach ($this->client->getAllContacts() as $eachContact) {\n // import contacts here\n $this->importContact(contactDto: $eachContact);\n $count++;\n }\n\n return $count;\n }\n\n public function syncContacts(Carbon $since, ?Carbon $to = null): int\n {\n $count = 0;\n $this->logger->info('[integration-app] Syncing contacts', [\n 'since' => $since,\n 'to' => $to,\n 'team_id' => $this->team?->getId(),\n ]);\n\n $params = [\n 'since' => $since,\n 'to' => $to,\n ];\n\n foreach ($this->client->getFilteredContacts($params) as $eachContact) {\n $this->importContact($eachContact);\n $count++;\n }\n\n $this->logger->info('[integration-app] Syncing contacts finished successfully', [\n 'since' => $since,\n 'to' => $to,\n 'team_id' => $this->team?->getId(),\n ]);\n\n return $count;\n }\n\n // Sync single records.\n public function syncContact(string $crmId): ?Contact\n {\n try {\n $contactRecord = $this->client->getSingleContact($crmId);\n if ($contactRecord === null) {\n return null;\n }\n\n return $this->importContact($contactRecord);\n } catch (RequestException) {\n return null;\n }\n }\n\n private function importContact(DTO\\Contact $contactDto): ?Contact\n {\n $createInternalAccount = false;\n\n /** @var CrmEntityRepository $crmEntityRepo */\n $crmEntityRepo = app(CrmEntityRepository::class);\n\n $accountId = $this->findMappedAccountId(\n pivotEntityId: $contactDto->externalId,\n externalAccountId: $contactDto->accountId,\n );\n $userId = $this->findMappedUserId($contactDto->ownerId);\n\n if ($accountId === null) {\n $this->logger->info('[integration-app] Importing contact, but related account cannot be found', [\n 'crm_provider_id' => $contactDto->externalId,\n 'raw_account_id' => $contactDto->accountId,\n 'name' => $contactDto->fullName,\n 'user_id' => $userId,\n ]);\n\n $createInternalAccount = true;\n }\n\n $data = [\n 'user_id' => $userId,\n 'account_id' => $accountId,\n 'crm_provider_id' => $contactDto->externalId,\n 'owner_id' => $contactDto->ownerId,\n 'name' => $contactDto->fullName !== null ? mb_substr($contactDto->fullName, 0, 100) : null,\n 'title' => $contactDto->title !== null ? mb_substr($contactDto->title, 0, 100) : null,\n 'email' => $contactDto->primaryEmail !== null ? mb_substr($contactDto->primaryEmail, 0, 191) : null,\n 'phone' => $contactDto->phone !== null ? mb_substr($contactDto->phone, 0, 25) : null,\n 'mobile_phone' => $contactDto->mobilePhone !== null ? mb_substr($contactDto->mobilePhone, 0, 25) : null,\n 'country_code' => $contactDto->countryCode !== null ? mb_substr($contactDto->countryCode, 0, 2) : null,\n 'remotely_created_at' => $contactDto->createdAt,\n 'photo_path' => '',\n ];\n\n $this->logger->info('[integration-app] Importing contact', [\n 'crm_provider_id' => $contactDto->externalId,\n 'team_id' => $this->team?->getId(),\n ]);\n\n $contact = $crmEntityRepo->importContact($this->getConfiguration(), $data);\n $this->mapExternalContact($contact);\n\n if ($createInternalAccount) {\n $this->createInternalAccountFromContact($contact)->getId();\n }\n\n return $contact;\n }\n\n /**\n * @param bool $matchFromOtherCrm - This parameter is intended to be manually used. It will help with\n * matching older opportunities if the team is transitioning from one CRM provider to another.\n */\n public function syncAllOpportunities(bool $matchFromOtherCrm = false): int\n {\n $count = 0;\n foreach ($this->client->getAllOpportunities() as $eachDeal) {\n $this->upsertOpportunity($eachDeal, $matchFromOtherCrm);\n $count++;\n }\n\n return $count;\n }\n\n public function syncOpportunities(array $parameters, ?string $strategy = null): int\n {\n $parameters['strategy'] = $strategy ?? OpportunitySyncStrategyResolver::LAST_MODIFIED_SYNC_OPPORTUNITY_STRATEGY;\n $count = 0;\n\n $this->logger->info('[integration-app] Syncing opportunities', [\n 'parameters' => $parameters,\n 'team_id' => $this->team?->getId(),\n ]);\n\n /** @var DTO\\Opportunity[] $pageResultData */\n foreach ($this->client->getFilteredOpportunities($parameters) as $pageResultData) {\n $externalAccounts = [];\n $externalContacts = [];\n\n foreach ($pageResultData as $eachRecord) {\n $externalAccounts[] = $eachRecord->accountId ?? null;\n $externalContacts[] = $eachRecord->contactId ?? null;\n }\n\n // Import missing contacts and account as early as possible\n $missingContacts = $this->identifyMissingContacts($externalContacts);\n if (! empty($missingContacts)) {\n $this->batchSyncContacts($missingContacts);\n }\n\n $missingAccounts = $this->identifyMissingAccounts($externalAccounts);\n if (! empty($missingAccounts)) {\n $this->batchSyncAccounts($missingAccounts);\n }\n\n foreach ($pageResultData as $eachRecord) {\n $this->upsertOpportunity($eachRecord);\n $count++;\n }\n }\n\n $this->logger->info('[integration-app] Syncing opportunities finished successfully', [\n 'parameters' => $parameters,\n 'team_id' => $this->team?->getId(),\n ]);\n\n return $count;\n }\n\n public function syncOpportunity(string $crmId): ?Opportunity\n {\n try {\n $opportunityRecord = $this->client->getSingleOpportunity($crmId);\n if ($opportunityRecord === null) {\n return null;\n }\n\n return $this->upsertOpportunity($opportunityRecord);\n } catch (RequestException) {\n return null;\n }\n }\n\n public function syncAllLeads(): int\n {\n if (isset($this->config->getSettings()['lead_sync_disabled'])) {\n $this->logger->info('[integration-app] Syncing leads disabled for the client', [\n 'team_id' => $this->team?->getId(),\n ]);\n\n return 0;\n }\n\n $count = 0;\n foreach ($this->client->getAllLeads() as $eachLead) {\n $this->importLead($eachLead);\n $count++;\n }\n\n return $count;\n }\n\n public function syncLeads(Carbon $since, ?Carbon $to = null, ?string $crmProfileId = null): int\n {\n if (isset($this->config->getSettings()['lead_sync_disabled'])) {\n $this->logger->info('[integration-app] Syncing leads disabled for the client', [\n 'team_id' => $this->team?->getId(),\n 'since' => $since,\n 'to' => $to,\n 'crm_profile_id' => $crmProfileId,\n ]);\n\n return 0;\n }\n\n $count = 0;\n $this->logger->info('[integration-app] Syncing leads', [\n 'since' => $since,\n 'to' => $to,\n 'crm_profile_id' => $crmProfileId,\n 'team_id' => $this->team?->getId(),\n ]);\n\n $filterData = [\n 'since' => $since,\n 'to' => $to,\n 'crm_profile_id' => $crmProfileId,\n 'converted' => 'both',\n ];\n\n foreach ($this->client->getFilteredLeads($filterData) as $eachLead) {\n $this->importLead($eachLead);\n $count++;\n }\n\n $this->logger->info('[integration-app] Syncing leads finished successfully', [\n 'since' => $since,\n 'to' => $to,\n 'team_id' => $this->team?->getId(),\n ]);\n\n return $count;\n }\n\n public function syncLead(string $crmId): ?Lead\n {\n if (isset($this->config->getSettings()['lead_sync_disabled'])) {\n $this->logger->info('[integration-app] Syncing leads disabled for the client', [\n 'team_id' => $this->team?->getId(),\n 'crm_id' => $crmId,\n ]);\n\n return null;\n }\n\n try {\n $leadRecord = $this->client->getSingleAndConvertLead($crmId);\n if ($leadRecord === null) {\n return null;\n }\n\n return $this->importLead($leadRecord);\n } catch (RequestException) {\n return null;\n }\n }\n\n private function importLead(DTO\\Lead $leadDto): ?Lead\n {\n /** @var CrmEntityRepository $crmEntityRepo */\n $crmEntityRepo = app(CrmEntityRepository::class);\n $userId = $this->findMappedUserId($leadDto->ownerId);\n\n $stage = null;\n if ($this->editionConfig->supportsStages()) {\n // Get the current stage.\n $stage = $crmEntityRepo->getStageForName(\n configuration: $this->config,\n name: $leadDto->status,\n type: Stage::TYPE_LEAD\n );\n }\n\n if ($stage === null && ! empty($leadDto->status)) {\n // Try to sync and import the lead stage by name only\n $stage = $this->syncStageByNameOnly($this->config, $leadDto->status, Stage::TYPE_LEAD);\n }\n\n $stageId = $stage?->id;\n\n $leadData = [\n 'team_id' => $this->team->getId(),\n 'crm_configuration_id' => $this->config->getId(),\n 'crm_provider_id' => $leadDto->externalId,\n 'name' => $leadDto->fullName,\n 'company' => $leadDto->companyName,\n 'owner_id' => $leadDto->ownerId,\n 'user_id' => $userId,\n 'stage_id' => $stageId,\n 'email' => $leadDto->primaryEmail,\n 'phone' => $leadDto->primaryPhone,\n 'mobile_phone' => $leadDto->secondaryPhone,\n 'title' => $leadDto->jobTitle,\n 'remotely_created_at' => $leadDto->createdAt,\n ];\n\n $convertedLeadData = $this->processConvertedLead($crmEntityRepo, $leadDto);\n $leadData = array_merge($leadData, $convertedLeadData);\n\n $this->logger->info('[integration-app] Importing lead', [\n 'crm_provider_id' => $leadDto->externalId,\n 'name' => $leadDto->primaryEmail,\n 'team_id' => $this->team?->getId(),\n ]);\n\n $lead = $crmEntityRepo->importLead($this->config, $leadData);\n\n $this->dispatchLeadConvertedEvent($lead);\n\n return $lead;\n }\n\n private function processConvertedLead(CrmEntityRepository $crmEntityRepo, DTO\\Lead $leadDto): array\n {\n if (! $leadDto->isConverted()) {\n return [];\n }\n\n $leadData = [\n 'converted_at' => $leadDto->getConvertedAt(),\n ];\n\n $this->decorateWithConvertedContact($crmEntityRepo, $leadDto, $leadData);\n $this->decorateWithConvertedAccount($crmEntityRepo, $leadDto, $leadData);\n $this->decorateWithConvertedOpportunity($crmEntityRepo, $leadDto, $leadData);\n\n return $leadData;\n }\n\n private function dispatchLeadConvertedEvent(Lead $lead): void\n {\n if ($lead->wasChanged('converted_at') && $lead->getConvertedAt() !== null) {\n event(new LeadConverted($lead));\n }\n }\n\n private function decorateWithConvertedContact(\n CrmEntityRepository $crmEntityRepo,\n DTO\\Lead $leadDto,\n array &$leadData\n ): void {\n if ($leadDto->getConvertedContactId() !== null) {\n $convertedContact = $crmEntityRepo->findContactByExternalId(\n $this->config,\n $leadDto->getConvertedContactId()\n );\n\n if ($convertedContact === null) {\n try {\n $convertedContact = $this->syncContact($leadDto->getConvertedContactId());\n } catch (\\Exception $exception) {\n $this->logger->error('[integration-app] Error syncing converted contact', [\n 'lead_id' => $leadDto->getExternalId(),\n 'crm_provider_id' => $leadDto->getConvertedContactId(),\n 'error' => $exception->getMessage(),\n ]);\n }\n }\n\n $leadData['converted_contact_id'] = $convertedContact?->getId();\n }\n }\n\n private function decorateWithConvertedAccount(\n CrmEntityRepository $crmEntityRepo,\n DTO\\Lead $leadDto,\n array &$leadData\n ): void {\n if ($leadDto->getConvertedAccountId() !== null) {\n $convertedAccount = $crmEntityRepo->findAccountByExternalId(\n $this->config,\n $leadDto->getConvertedAccountId()\n );\n\n if ($convertedAccount === null) {\n try {\n $convertedAccount = $this->syncAccount($leadDto->getConvertedAccountId());\n } catch (\\Exception $exception) {\n $this->logger->error('[integration-app] Error syncing converted account', [\n 'lead_id' => $leadDto->getExternalId(),\n 'crm_provider_id' => $leadDto->getConvertedAccountId(),\n 'error' => $exception->getMessage(),\n ]);\n }\n }\n\n $leadData['converted_account_id'] = $convertedAccount?->getId();\n }\n }\n\n private function decorateWithConvertedOpportunity(\n CrmEntityRepository $crmEntityRepo,\n DTO\\Lead $leadDto,\n array &$leadData\n ): void {\n if ($leadDto->getConvertedOpportunityId() !== null) {\n $convertedOpportunity = $crmEntityRepo->findOpportunityByExternalId(\n $this->config,\n $leadDto->getConvertedOpportunityId()\n );\n\n if ($convertedOpportunity === null) {\n try {\n $convertedOpportunity = $this->syncOpportunity($leadDto->getConvertedOpportunityId());\n } catch (\\Exception $exception) {\n $this->logger->error('[integration-app] Error syncing converted opportunity', [\n 'lead_id' => $leadDto->getExternalId(),\n 'crm_provider_id' => $leadDto->getConvertedOpportunityId(),\n 'error' => $exception->getMessage(),\n ]);\n }\n }\n\n $leadData['converted_opportunity_id'] = $convertedOpportunity?->getId();\n }\n }\n\n /**\n * @throws GuzzleException\n */\n public function importStages(?array $types = null, ?string $missingStageName = null): ?Stage\n {\n if (! $this->editionConfig->supportsStages()) {\n return null;\n }\n\n $missingStage = null;\n $stagesCollection = $this->client->getAllDealsStages();\n foreach ($stagesCollection as $eachStage) {\n $stage = $this->importStage($eachStage);\n\n if ($stage->getName() === $missingStageName) {\n $missingStage = $stage;\n }\n }\n\n return $missingStage;\n }\n\n private function importStage(DTO\\EntityStage $stageDto): Stage\n {\n /** @var CrmEntityRepository $crmEntityRepo */\n $crmEntityRepo = app(CrmEntityRepository::class);\n $objectType = $stageDto->type ?? Stage::TYPE_OPPORTUNITY;\n\n $stageData = [\n 'crm_provider_id' => $stageDto->externalId,\n 'name' => mb_strimwidth($stageDto->apiName ?? $stageDto->name, 0, 50),\n 'label' => mb_strimwidth($stageDto->masterLabel ?? $stageDto->name, 0, 191),\n 'sequence' => $stageDto->sortOrder ?? 0,\n 'probability' => $stageDto->defaultProbability ?? null,\n 'is_selectable' => $stageDto->isActive ?? 0,\n 'type' => $objectType,\n ];\n\n $this->logger->info('[integration-app] Importing stage', [\n 'crm_provider_id' => $stageDto->externalId,\n 'name' => $stageDto->name,\n 'team_id' => $this->team?->getId(),\n ]);\n\n $stage = $crmEntityRepo->importStage($this->config, $objectType, $stageData);\n\n // Include newly imported stages to the map\n $this->mapExternalStage($stage);\n\n return $stage;\n }\n\n /**\n * Attach a stage to a default business process.\n * This method is used only in Zoho implementation\n * where both supportsPipelines and supportsPipelines are false\n */\n public function syncBusinessProcessStages(int $stageId): void\n {\n /** @var StageRepository $stageRepository */\n $stageRepository = app(StageRepository::class);\n $processName = 'DefaultOpportunityProcess';\n $data = [\n 'team_id' => $this->team->getId(),\n 'name' => $processName,\n 'type' => Stage::TYPE_OPPORTUNITY,\n 'is_selectable' => true,\n ];\n\n $businessProcess = $stageRepository->findOrCreateBusinessProcess(\n $this->config,\n $processName,\n $data\n );\n\n $businessProcess->stages()->attach($stageId);\n }\n\n /**\n * bool $matchFromOtherCrm\n * When inserting a deal match try to match it to an existing from other CRM within the same team.\n * - This parameter is intended to be manually used only. It will help with\n * matching older opportunities if the team is transitioning from one CRM provider to another.\n */\n private function upsertOpportunity(DTO\\Opportunity $opportunityDto, bool $matchFromOtherCrm = false): ?Opportunity\n {\n $this->logger->info('[integration-app] Importing opportunity', [\n 'crm_provider_id' => $opportunityDto->externalId,\n 'team_id' => $this->team->getId(),\n ]);\n\n if ($this->config === null) {\n $this->logger->warning('[integration-app] Opportunity missing config');\n\n return null;\n }\n\n $stageId = $this->findOpportunityStageId(\n externalStageId: $opportunityDto->stageId,\n stageName: $opportunityDto->stageName\n );\n\n // temporary detect memory usage\n $this->logger->info('[integration-app] Stage ID', [\n 'memory_usage' => memory_get_usage(),\n 'memory_real_usage' => memory_get_usage(true),\n 'crm_provider_id' => $opportunityDto->externalId,\n 'stage_id' => $stageId,\n ]);\n\n $accountId = $this->findAccountId(\n pivotEntityId: $opportunityDto->externalId,\n externalAccountId: $opportunityDto->accountId,\n externalContactId: $opportunityDto->contactId,\n );\n\n $this->logger->info('[integration-app] Account ID', [\n 'memory_usage' => memory_get_usage(),\n 'memory_real_usage' => memory_get_usage(true),\n 'crm_provider_id' => $opportunityDto->externalId,\n 'account_id' => $accountId,\n ]);\n\n if ($stageId === null || $accountId === null) {\n $this->logger->warning('[integration-app] Opportunity missing data', [\n 'stageId' => $stageId,\n 'accountId' => $accountId,\n 'externalId' => $opportunityDto->externalId,\n ]);\n\n return null;\n }\n\n $userId = $this->findMappedUserId(externalUserId: $opportunityDto->ownerId);\n\n $data = [\n 'crm_provider_id' => $opportunityDto->externalId,\n 'team_id' => $this->team->getId(),\n 'account_id' => $accountId,\n 'user_id' => $userId,\n 'owner_id' => $opportunityDto->ownerId,\n 'name' => mb_strimwidth($opportunityDto->name, 0, 128),\n 'value' => $opportunityDto->amount,\n 'currency_code' => CurrencyFormatter::formatCode($this->getCurrencyIso($opportunityDto)),\n 'close_date' => $opportunityDto->closeDate,\n 'is_closed' => $opportunityDto->closed,\n 'is_won' => $opportunityDto->won,\n 'stage_id' => $stageId,\n 'record_type_id' => null,\n 'remotely_created_at' => $opportunityDto->createdAt,\n 'probability' => $opportunityDto->probability,\n ];\n\n /** @var CrmEntityRepository $crmEntityRepo */\n $crmEntityRepo = app(CrmEntityRepository::class);\n $opportunity = $crmEntityRepo->importOpportunity(\n $this->config,\n $data,\n $matchFromOtherCrm,\n $opportunityDto->name,\n );\n\n // Import external fields into crm_field_data if present\n $crmFields = $this->getOpportunitySyncableFields();\n $this->importOpportunityFieldData($opportunityDto, $crmFields, $opportunity->getId());\n\n if ($opportunityDto->deleted === true) {\n $opportunity->delete();\n\n return $opportunity;\n }\n\n if ($opportunity->wasRecentlyCreated) {\n MatchActivitiesToNewOpportunity::dispatch($opportunity->getId());\n }\n\n return $opportunity;\n }\n\n private function findOpportunityStageId(?string $externalStageId, ?string $stageName): ?int\n {\n $stageId = null;\n\n if ($this->editionConfig->supportsStages()) {\n $stageId = $this->findMappedStageId(externalStageId: $externalStageId, type: Stage::TYPE_OPPORTUNITY);\n\n if ($stageId === null) {\n $stageId = $this->importStages(types: [Stage::TYPE_OPPORTUNITY], missingStageName: $stageName)?->id;\n }\n }\n\n if ($stageId === null && $stageName !== null) {\n $stageId = $this->syncStageByNameOnly(\n configuration: $this->config,\n stageName: $stageName,\n type: Stage::TYPE_OPPORTUNITY\n )?->id;\n }\n\n return $stageId;\n }\n\n private function importOpportunityFieldData(\n DTO\\Opportunity $opportunityDto,\n array $crmFields,\n int $opportunityId\n ): void {\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n /** @var FieldDataRepository $fieldDataRepository */\n $fieldDataRepository = app(FieldDataRepository::class);\n\n foreach ($crmFields as $crmField) {\n if (! property_exists($opportunityDto, $crmField)) {\n continue;\n }\n\n if ($opportunityDto->{$crmField} === null) {\n continue;\n }\n\n $field = $fieldRepository->findFieldByCrmIdAndObjectType(\n $this->config,\n $crmField,\n Field::OBJECT_OPPORTUNITY\n );\n\n if (! $field instanceof Field) {\n $this->logger->info('Field not found', [\n 'field' => $crmField,\n 'config' => $this->config->getId(),\n ]);\n\n continue;\n }\n\n $entities = $field->getEntities();\n if ($entities->isEmpty()) {\n $this->logger->info('Field has no entities', [\n 'field' => $crmField,\n 'config' => $this->config->getId(),\n ]);\n\n continue;\n }\n\n if ($entities->count() > 1) {\n $this->logger->info('Field has multiple entities', [\n 'field' => $crmField,\n 'config' => $this->config->getId(),\n ]);\n\n continue;\n }\n\n /** @var LayoutEntity|null $entity */\n $entity = $entities->first();\n if (! $entity instanceof LayoutEntity) {\n continue;\n }\n\n $value = (string) $opportunityDto->{$crmField};\n\n $fieldDataRepository->updateOrCreateFieldData(\n $entity,\n $opportunityId,\n $value,\n );\n }\n }\n\n private function getCurrencyIso(DTO\\Opportunity $opportunityDto): ?string\n {\n if ($opportunityDto->currencyIso !== null) {\n return $opportunityDto->currencyIso;\n }\n\n // Fallback to billing currency\n return $this->config->getDefaultCurrency();\n }\n\n /**\n * Some CRM providers do not support listing all stages.\n * Additionally, they may not even supply us with a stage ID when the stage is supplied as a property of the deal.\n * In that case, we will usually have only a stage name.\n * In order to import such stages only once, we will slugify them and produce \"external ID\" on our own.\n */\n private function syncStageByNameOnly(Configuration $configuration, string $stageName, ?string $type = null): ?Stage\n {\n // @TEMP For testing purposes only!!!\n // Revert when we find suitable way to fetch the stage\n /** @var CrmEntityRepository $crmEntityRepo */\n $crmEntityRepo = app(CrmEntityRepository::class);\n $stage = $crmEntityRepo->getStageForName($configuration, $stageName, $type);\n if ($stage !== null) {\n return $stage;\n }\n\n // if there is other legitimate way to fetch the stage skip.\n if ($this->editionConfig->supportsPipelines() ||\n $this->editionConfig->supportsStages()\n ) {\n return null;\n }\n\n /** @var CrmEntityRepository $crmEntityRepo */\n $crmEntityRepo = app(CrmEntityRepository::class);\n $stage = $crmEntityRepo->getStageForName($configuration, $stageName, $type);\n\n // Create the stage if it does not exist already\n if ($stage === null) {\n $stageDto = new DTO\\EntityStage();\n $stageDto->externalId = $stageName;\n $stageDto->masterLabel = Str::slug($stageName);\n $stageDto->name = $stageName;\n\n $stageDto->type = $type;\n\n $stage = $this->importStage($stageDto);\n\n if ($type === Stage::TYPE_OPPORTUNITY) {\n $this->syncBusinessProcessStages($stage->getId());\n }\n }\n\n return $stage;\n }\n\n private function findAccountId(\n string $pivotEntityId,\n ?string $externalAccountId = null,\n ?string $externalContactId = null,\n bool $skipAccountSync = false,\n ): ?int {\n $accountId = $this->findMappedAccountId(\n pivotEntityId: $pivotEntityId,\n externalAccountId: $externalAccountId,\n skipAccountSync: $skipAccountSync,\n );\n\n if ($accountId !== null) {\n return $accountId;\n }\n\n /**\n * The deal probably does not have an Account assigned.\n * In order to not break the existing import, we will try to find a contact\n * and create an Account with the same data.\n */\n if (! empty($externalContactId)) {\n // In rare cases the contact's external id matches our account id, whe :(\n $this->logger->info('[integration-app] fallback Account', ['contact_id' => $externalContactId]);\n\n $accountId = $this->findMappedAccountId(\n pivotEntityId: $pivotEntityId,\n externalAccountId: $externalContactId,\n skipAccountSync: true,\n );\n\n if ($accountId !== null) {\n return $accountId;\n }\n\n $this->logger->info('[integration-app] create Account from Contact', ['contact_id' => $externalContactId]);\n $crmEntityRepo = app(CrmEntityRepository::class);\n\n $contact = $crmEntityRepo->findContactByExternalId($this->config, $externalContactId);\n if ($contact !== null) {\n return $this->createInternalAccountFromContact($contact)->getId();\n }\n }\n\n return null;\n }\n\n private function createInternalAccountFromContact(Contact $contact): Account\n {\n $this->logger->info('[integration-app] Create internal account from contact', [\n 'team_id' => $this->team?->getId(),\n 'contact_id' => $contact->getId(),\n 'crm_provider_id' => $contact->getCrmProviderId(),\n ]);\n\n $data = [\n 'crm_configuration_id' => $this->config->getId(),\n 'team_id' => $this->config->getTeamId(),\n 'crm_provider_id' => $contact->getCrmProviderId(),\n 'user_id' => $contact->getUserId(),\n 'owner_id' => $contact->getOwnerId(),\n 'name' => $contact->getName(),\n 'phone' => $contact->getPhone(),\n 'country_code' => $contact->getCountryCode(),\n 'remotely_created_at' => $contact->getRemotelyCreatedAt(),\n 'is_internal' => 1,\n ];\n\n /** @var CrmEntityRepository $crmEntityRepo */\n $crmEntityRepo = app(CrmEntityRepository::class);\n $account = $crmEntityRepo->importAccount($this->config, $data);\n\n if ($contact->account_id === null) {\n $contact->account_id = $account->getId();\n $contact->save();\n }\n\n $this->mapExternalAccount($account);\n\n return $account;\n }\n\n private function batchSyncContacts(array $externalContactIds): void\n {\n $this->logger->info('[integration-app] Syncing batch contacts', [\n 'batch_contacts' => implode(',', $externalContactIds),\n 'team_id' => $this->team?->getId(),\n ]);\n\n /** IntegrationApp allows up to 100 IDs passed as a batch. */\n $chunkedContacts = array_chunk($externalContactIds, self::CHUNK_SIZE);\n foreach ($chunkedContacts as $contactGroup) {\n /** @var DTO\\Contact[] $pageResultData */\n foreach ($this->client->getBatchContactsById($contactGroup) as $pageResultData) {\n $externalAccounts = [];\n foreach ($pageResultData as $eachRecord) {\n $externalAccounts[] = $eachRecord->accountId ?? null;\n }\n\n $missingAccounts = $this->identifyMissingAccounts($externalAccounts);\n if (! empty($missingAccounts)) {\n $this->batchSyncAccounts($missingAccounts);\n }\n\n foreach ($pageResultData as $eachRecord) {\n $this->importContact($eachRecord);\n }\n }\n }\n }\n\n private function batchSyncAccounts(array $externalAccountIds): void\n {\n $this->logger->info('[integration-app] Syncing batch accounts', [\n 'batch_contacts' => implode(',', $externalAccountIds),\n 'team_id' => $this->team?->getId(),\n ]);\n\n /** IntegrationApp allows up to 100 IDs passed as a batch. */\n $chunkedAccounts = array_chunk($externalAccountIds, self::CHUNK_SIZE);\n foreach ($chunkedAccounts as $accountGroup) {\n /** @var DTO\\Account[] $pageResultData */\n foreach ($this->client->getBatchAccountsById($accountGroup) as $pageResultData) {\n foreach ($pageResultData as $eachRecord) {\n $this->importAccount($eachRecord);\n }\n }\n }\n }\n\n /**\n * Identify all contacts Ids, that are not found in our database.\n * Scoped to the current batch so memory and query cost scale with batch size,\n * not with tenant size.\n *\n * @param array<?string> $contacts\n *\n * @return list<string>\n */\n private function identifyMissingContacts(array $contacts): array\n {\n $wanted = array_values(array_unique(array_filter($contacts)));\n if ($wanted === []) {\n return [];\n }\n\n /** @var CrmEntityRepository $crmEntityRepo */\n $crmEntityRepo = app(CrmEntityRepository::class);\n $existing = $crmEntityRepo->getExistingContactCrmIds($this->config, $wanted);\n\n return array_values(array_diff($wanted, $existing));\n }\n\n /**\n * Identify all account Ids, that are not found in our database.\n * Scoped to the current batch so memory and query cost scale with batch size,\n * not with tenant size.\n *\n * @param array<?string> $accounts\n *\n * @return list<string>\n */\n private function identifyMissingAccounts(array $accounts): array\n {\n $wanted = array_values(array_unique(array_filter($accounts)));\n if ($wanted === []) {\n return [];\n }\n\n /** @var CrmEntityRepository $crmEntityRepo */\n $crmEntityRepo = app(CrmEntityRepository::class);\n $existing = $crmEntityRepo->getExistingAccountCrmIds($this->config, $wanted);\n\n return array_values(array_diff($wanted, $existing));\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\IntegrationApp\\ServiceTraits;\n\nuse Carbon\\Carbon;\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse GuzzleHttp\\Exception\\RequestException;\nuse Illuminate\\Support\\Str;\nuse Jiminny\\Events\\Activities\\Crm\\LeadConverted;\nuse Jiminny\\Models\\Contact;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\LayoutEntity;\nuse Jiminny\\Models\\Lead;\nuse Jiminny\\Models\\Opportunity;\nuse Jiminny\\Models\\Stage;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Models\\Account;\nuse Jiminny\\Jobs\\Crm\\MatchActivitiesToNewOpportunity;\nuse Jiminny\\Repositories\\Crm\\CrmEntityRepository;\nuse Jiminny\\Repositories\\Crm\\FieldDataRepository;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Repositories\\Crm\\StageRepository;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\Config\\IntegrationConfigInterface as IntegrationConfig;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DataClient;\nuse Jiminny\\Services\\Crm\\OpportunitySyncStrategyResolver;\nuse Jiminny\\Utils\\CurrencyFormatter;\nuse Psr\\Log\\LoggerInterface;\n\n/**\n * This trait follows closely the contract SyncCrmEntitiesInterface\n */\ntrait SyncCrmEntitiesTrait\n{\n use ExternalMapsTrait;\n\n private const int CHUNK_SIZE = 100;\n\n public ?Team $team = null;\n public ?Configuration $config;\n public ?IntegrationConfig $editionConfig;\n protected LoggerInterface $logger;\n /**\n * @var DataClient\n */\n protected $client;\n\n public function syncAllAccounts(): int\n {\n $count = 0;\n foreach ($this->client->getAllAccounts() as $eachAccount) {\n $this->importAccount($eachAccount);\n $count++;\n }\n\n return $count;\n }\n\n public function syncAccounts(Carbon $since, ?Carbon $to = null): int\n {\n $count = 0;\n $this->logger->info('[integration-app] Syncing accounts', [\n 'since' => $since,\n 'to' => $to,\n 'team_id' => $this->team?->getId(),\n ]);\n\n $params = [\n 'since' => $since,\n 'to' => $to,\n ];\n\n /** @var DTO\\Account $eachAccount*/\n foreach ($this->client->getFilteredAccounts($params) as $eachAccount) {\n $this->importAccount($eachAccount);\n $count++;\n }\n\n $this->logger->info('[integration-app] Syncing accounts finished successfully', [\n 'since' => $since,\n 'to' => $to,\n 'team_id' => $this->team?->getId(),\n ]);\n\n return $count;\n }\n\n public function syncAccount(string $crmId): ?Account\n {\n try {\n $accountDto = $this->client->getSingleAccount($crmId);\n if ($accountDto === null) {\n return null;\n }\n\n return $this->importAccount($accountDto);\n } catch (RequestException) {\n return null;\n }\n }\n\n private function importAccount(DTO\\Account $accountDto): Account\n {\n /** @var CrmEntityRepository $crmEntityRepo */\n $crmEntityRepo = app(CrmEntityRepository::class);\n $data = [\n 'crm_provider_id' => $accountDto->externalId,\n 'user_id' => $this->findMappedUserId($accountDto->ownerId),\n 'owner_id' => $accountDto->ownerId,\n 'name' => mb_substr($accountDto->name, 0, 191),\n 'phone' => $accountDto->phone !== null ? mb_substr($accountDto->phone, 0, 25) : null,\n 'industry' => $accountDto->industry !== null ? mb_substr($accountDto->industry, 0, 191) : null,\n 'domain' => $accountDto->websiteUrl !== null ? mb_substr($accountDto->websiteUrl, 0, 191) : null,\n 'country_code' => $accountDto->countryCode,\n 'remotely_created_at' => $accountDto->createdAt,\n ];\n\n $this->logger->info('[integration-app] Importing account', [\n 'crm_provider_id' => $accountDto->externalId,\n 'team_id' => $this->team?->getId(),\n ]);\n\n $account = $crmEntityRepo->importAccount($this->getConfiguration(), $data);\n $this->mapExternalAccount($account);\n\n return $account;\n }\n\n // Sync multiple records.\n public function syncAllContacts(): int\n {\n $count = 0;\n foreach ($this->client->getAllContacts() as $eachContact) {\n // import contacts here\n $this->importContact(contactDto: $eachContact);\n $count++;\n }\n\n return $count;\n }\n\n public function syncContacts(Carbon $since, ?Carbon $to = null): int\n {\n $count = 0;\n $this->logger->info('[integration-app] Syncing contacts', [\n 'since' => $since,\n 'to' => $to,\n 'team_id' => $this->team?->getId(),\n ]);\n\n $params = [\n 'since' => $since,\n 'to' => $to,\n ];\n\n foreach ($this->client->getFilteredContacts($params) as $eachContact) {\n $this->importContact($eachContact);\n $count++;\n }\n\n $this->logger->info('[integration-app] Syncing contacts finished successfully', [\n 'since' => $since,\n 'to' => $to,\n 'team_id' => $this->team?->getId(),\n ]);\n\n return $count;\n }\n\n // Sync single records.\n public function syncContact(string $crmId): ?Contact\n {\n try {\n $contactRecord = $this->client->getSingleContact($crmId);\n if ($contactRecord === null) {\n return null;\n }\n\n return $this->importContact($contactRecord);\n } catch (RequestException) {\n return null;\n }\n }\n\n private function importContact(DTO\\Contact $contactDto): ?Contact\n {\n $createInternalAccount = false;\n\n /** @var CrmEntityRepository $crmEntityRepo */\n $crmEntityRepo = app(CrmEntityRepository::class);\n\n $accountId = $this->findMappedAccountId(\n pivotEntityId: $contactDto->externalId,\n externalAccountId: $contactDto->accountId,\n );\n $userId = $this->findMappedUserId($contactDto->ownerId);\n\n if ($accountId === null) {\n $this->logger->info('[integration-app] Importing contact, but related account cannot be found', [\n 'crm_provider_id' => $contactDto->externalId,\n 'raw_account_id' => $contactDto->accountId,\n 'name' => $contactDto->fullName,\n 'user_id' => $userId,\n ]);\n\n $createInternalAccount = true;\n }\n\n $data = [\n 'user_id' => $userId,\n 'account_id' => $accountId,\n 'crm_provider_id' => $contactDto->externalId,\n 'owner_id' => $contactDto->ownerId,\n 'name' => $contactDto->fullName !== null ? mb_substr($contactDto->fullName, 0, 100) : null,\n 'title' => $contactDto->title !== null ? mb_substr($contactDto->title, 0, 100) : null,\n 'email' => $contactDto->primaryEmail !== null ? mb_substr($contactDto->primaryEmail, 0, 191) : null,\n 'phone' => $contactDto->phone !== null ? mb_substr($contactDto->phone, 0, 25) : null,\n 'mobile_phone' => $contactDto->mobilePhone !== null ? mb_substr($contactDto->mobilePhone, 0, 25) : null,\n 'country_code' => $contactDto->countryCode !== null ? mb_substr($contactDto->countryCode, 0, 2) : null,\n 'remotely_created_at' => $contactDto->createdAt,\n 'photo_path' => '',\n ];\n\n $this->logger->info('[integration-app] Importing contact', [\n 'crm_provider_id' => $contactDto->externalId,\n 'team_id' => $this->team?->getId(),\n ]);\n\n $contact = $crmEntityRepo->importContact($this->getConfiguration(), $data);\n $this->mapExternalContact($contact);\n\n if ($createInternalAccount) {\n $this->createInternalAccountFromContact($contact)->getId();\n }\n\n return $contact;\n }\n\n /**\n * @param bool $matchFromOtherCrm - This parameter is intended to be manually used. It will help with\n * matching older opportunities if the team is transitioning from one CRM provider to another.\n */\n public function syncAllOpportunities(bool $matchFromOtherCrm = false): int\n {\n $count = 0;\n foreach ($this->client->getAllOpportunities() as $eachDeal) {\n $this->upsertOpportunity($eachDeal, $matchFromOtherCrm);\n $count++;\n }\n\n return $count;\n }\n\n public function syncOpportunities(array $parameters, ?string $strategy = null): int\n {\n $parameters['strategy'] = $strategy ?? OpportunitySyncStrategyResolver::LAST_MODIFIED_SYNC_OPPORTUNITY_STRATEGY;\n $count = 0;\n\n $this->logger->info('[integration-app] Syncing opportunities', [\n 'parameters' => $parameters,\n 'team_id' => $this->team?->getId(),\n ]);\n\n /** @var DTO\\Opportunity[] $pageResultData */\n foreach ($this->client->getFilteredOpportunities($parameters) as $pageResultData) {\n $externalAccounts = [];\n $externalContacts = [];\n\n foreach ($pageResultData as $eachRecord) {\n $externalAccounts[] = $eachRecord->accountId ?? null;\n $externalContacts[] = $eachRecord->contactId ?? null;\n }\n\n // Import missing contacts and account as early as possible\n $missingContacts = $this->identifyMissingContacts($externalContacts);\n if (! empty($missingContacts)) {\n $this->batchSyncContacts($missingContacts);\n }\n\n $missingAccounts = $this->identifyMissingAccounts($externalAccounts);\n if (! empty($missingAccounts)) {\n $this->batchSyncAccounts($missingAccounts);\n }\n\n foreach ($pageResultData as $eachRecord) {\n $this->upsertOpportunity($eachRecord);\n $count++;\n }\n }\n\n $this->logger->info('[integration-app] Syncing opportunities finished successfully', [\n 'parameters' => $parameters,\n 'team_id' => $this->team?->getId(),\n ]);\n\n return $count;\n }\n\n public function syncOpportunity(string $crmId): ?Opportunity\n {\n try {\n $opportunityRecord = $this->client->getSingleOpportunity($crmId);\n if ($opportunityRecord === null) {\n return null;\n }\n\n return $this->upsertOpportunity($opportunityRecord);\n } catch (RequestException) {\n return null;\n }\n }\n\n public function syncAllLeads(): int\n {\n if (isset($this->config->getSettings()['lead_sync_disabled'])) {\n $this->logger->info('[integration-app] Syncing leads disabled for the client', [\n 'team_id' => $this->team?->getId(),\n ]);\n\n return 0;\n }\n\n $count = 0;\n foreach ($this->client->getAllLeads() as $eachLead) {\n $this->importLead($eachLead);\n $count++;\n }\n\n return $count;\n }\n\n public function syncLeads(Carbon $since, ?Carbon $to = null, ?string $crmProfileId = null): int\n {\n if (isset($this->config->getSettings()['lead_sync_disabled'])) {\n $this->logger->info('[integration-app] Syncing leads disabled for the client', [\n 'team_id' => $this->team?->getId(),\n 'since' => $since,\n 'to' => $to,\n 'crm_profile_id' => $crmProfileId,\n ]);\n\n return 0;\n }\n\n $count = 0;\n $this->logger->info('[integration-app] Syncing leads', [\n 'since' => $since,\n 'to' => $to,\n 'crm_profile_id' => $crmProfileId,\n 'team_id' => $this->team?->getId(),\n ]);\n\n $filterData = [\n 'since' => $since,\n 'to' => $to,\n 'crm_profile_id' => $crmProfileId,\n 'converted' => 'both',\n ];\n\n foreach ($this->client->getFilteredLeads($filterData) as $eachLead) {\n $this->importLead($eachLead);\n $count++;\n }\n\n $this->logger->info('[integration-app] Syncing leads finished successfully', [\n 'since' => $since,\n 'to' => $to,\n 'team_id' => $this->team?->getId(),\n ]);\n\n return $count;\n }\n\n public function syncLead(string $crmId): ?Lead\n {\n if (isset($this->config->getSettings()['lead_sync_disabled'])) {\n $this->logger->info('[integration-app] Syncing leads disabled for the client', [\n 'team_id' => $this->team?->getId(),\n 'crm_id' => $crmId,\n ]);\n\n return null;\n }\n\n try {\n $leadRecord = $this->client->getSingleAndConvertLead($crmId);\n if ($leadRecord === null) {\n return null;\n }\n\n return $this->importLead($leadRecord);\n } catch (RequestException) {\n return null;\n }\n }\n\n private function importLead(DTO\\Lead $leadDto): ?Lead\n {\n /** @var CrmEntityRepository $crmEntityRepo */\n $crmEntityRepo = app(CrmEntityRepository::class);\n $userId = $this->findMappedUserId($leadDto->ownerId);\n\n $stage = null;\n if ($this->editionConfig->supportsStages()) {\n // Get the current stage.\n $stage = $crmEntityRepo->getStageForName(\n configuration: $this->config,\n name: $leadDto->status,\n type: Stage::TYPE_LEAD\n );\n }\n\n if ($stage === null && ! empty($leadDto->status)) {\n // Try to sync and import the lead stage by name only\n $stage = $this->syncStageByNameOnly($this->config, $leadDto->status, Stage::TYPE_LEAD);\n }\n\n $stageId = $stage?->id;\n\n $leadData = [\n 'team_id' => $this->team->getId(),\n 'crm_configuration_id' => $this->config->getId(),\n 'crm_provider_id' => $leadDto->externalId,\n 'name' => $leadDto->fullName,\n 'company' => $leadDto->companyName,\n 'owner_id' => $leadDto->ownerId,\n 'user_id' => $userId,\n 'stage_id' => $stageId,\n 'email' => $leadDto->primaryEmail,\n 'phone' => $leadDto->primaryPhone,\n 'mobile_phone' => $leadDto->secondaryPhone,\n 'title' => $leadDto->jobTitle,\n 'remotely_created_at' => $leadDto->createdAt,\n ];\n\n $convertedLeadData = $this->processConvertedLead($crmEntityRepo, $leadDto);\n $leadData = array_merge($leadData, $convertedLeadData);\n\n $this->logger->info('[integration-app] Importing lead', [\n 'crm_provider_id' => $leadDto->externalId,\n 'name' => $leadDto->primaryEmail,\n 'team_id' => $this->team?->getId(),\n ]);\n\n $lead = $crmEntityRepo->importLead($this->config, $leadData);\n\n $this->dispatchLeadConvertedEvent($lead);\n\n return $lead;\n }\n\n private function processConvertedLead(CrmEntityRepository $crmEntityRepo, DTO\\Lead $leadDto): array\n {\n if (! $leadDto->isConverted()) {\n return [];\n }\n\n $leadData = [\n 'converted_at' => $leadDto->getConvertedAt(),\n ];\n\n $this->decorateWithConvertedContact($crmEntityRepo, $leadDto, $leadData);\n $this->decorateWithConvertedAccount($crmEntityRepo, $leadDto, $leadData);\n $this->decorateWithConvertedOpportunity($crmEntityRepo, $leadDto, $leadData);\n\n return $leadData;\n }\n\n private function dispatchLeadConvertedEvent(Lead $lead): void\n {\n if ($lead->wasChanged('converted_at') && $lead->getConvertedAt() !== null) {\n event(new LeadConverted($lead));\n }\n }\n\n private function decorateWithConvertedContact(\n CrmEntityRepository $crmEntityRepo,\n DTO\\Lead $leadDto,\n array &$leadData\n ): void {\n if ($leadDto->getConvertedContactId() !== null) {\n $convertedContact = $crmEntityRepo->findContactByExternalId(\n $this->config,\n $leadDto->getConvertedContactId()\n );\n\n if ($convertedContact === null) {\n try {\n $convertedContact = $this->syncContact($leadDto->getConvertedContactId());\n } catch (\\Exception $exception) {\n $this->logger->error('[integration-app] Error syncing converted contact', [\n 'lead_id' => $leadDto->getExternalId(),\n 'crm_provider_id' => $leadDto->getConvertedContactId(),\n 'error' => $exception->getMessage(),\n ]);\n }\n }\n\n $leadData['converted_contact_id'] = $convertedContact?->getId();\n }\n }\n\n private function decorateWithConvertedAccount(\n CrmEntityRepository $crmEntityRepo,\n DTO\\Lead $leadDto,\n array &$leadData\n ): void {\n if ($leadDto->getConvertedAccountId() !== null) {\n $convertedAccount = $crmEntityRepo->findAccountByExternalId(\n $this->config,\n $leadDto->getConvertedAccountId()\n );\n\n if ($convertedAccount === null) {\n try {\n $convertedAccount = $this->syncAccount($leadDto->getConvertedAccountId());\n } catch (\\Exception $exception) {\n $this->logger->error('[integration-app] Error syncing converted account', [\n 'lead_id' => $leadDto->getExternalId(),\n 'crm_provider_id' => $leadDto->getConvertedAccountId(),\n 'error' => $exception->getMessage(),\n ]);\n }\n }\n\n $leadData['converted_account_id'] = $convertedAccount?->getId();\n }\n }\n\n private function decorateWithConvertedOpportunity(\n CrmEntityRepository $crmEntityRepo,\n DTO\\Lead $leadDto,\n array &$leadData\n ): void {\n if ($leadDto->getConvertedOpportunityId() !== null) {\n $convertedOpportunity = $crmEntityRepo->findOpportunityByExternalId(\n $this->config,\n $leadDto->getConvertedOpportunityId()\n );\n\n if ($convertedOpportunity === null) {\n try {\n $convertedOpportunity = $this->syncOpportunity($leadDto->getConvertedOpportunityId());\n } catch (\\Exception $exception) {\n $this->logger->error('[integration-app] Error syncing converted opportunity', [\n 'lead_id' => $leadDto->getExternalId(),\n 'crm_provider_id' => $leadDto->getConvertedOpportunityId(),\n 'error' => $exception->getMessage(),\n ]);\n }\n }\n\n $leadData['converted_opportunity_id'] = $convertedOpportunity?->getId();\n }\n }\n\n /**\n * @throws GuzzleException\n */\n public function importStages(?array $types = null, ?string $missingStageName = null): ?Stage\n {\n if (! $this->editionConfig->supportsStages()) {\n return null;\n }\n\n $missingStage = null;\n $stagesCollection = $this->client->getAllDealsStages();\n foreach ($stagesCollection as $eachStage) {\n $stage = $this->importStage($eachStage);\n\n if ($stage->getName() === $missingStageName) {\n $missingStage = $stage;\n }\n }\n\n return $missingStage;\n }\n\n private function importStage(DTO\\EntityStage $stageDto): Stage\n {\n /** @var CrmEntityRepository $crmEntityRepo */\n $crmEntityRepo = app(CrmEntityRepository::class);\n $objectType = $stageDto->type ?? Stage::TYPE_OPPORTUNITY;\n\n $stageData = [\n 'crm_provider_id' => $stageDto->externalId,\n 'name' => mb_strimwidth($stageDto->apiName ?? $stageDto->name, 0, 50),\n 'label' => mb_strimwidth($stageDto->masterLabel ?? $stageDto->name, 0, 191),\n 'sequence' => $stageDto->sortOrder ?? 0,\n 'probability' => $stageDto->defaultProbability ?? null,\n 'is_selectable' => $stageDto->isActive ?? 0,\n 'type' => $objectType,\n ];\n\n $this->logger->info('[integration-app] Importing stage', [\n 'crm_provider_id' => $stageDto->externalId,\n 'name' => $stageDto->name,\n 'team_id' => $this->team?->getId(),\n ]);\n\n $stage = $crmEntityRepo->importStage($this->config, $objectType, $stageData);\n\n // Include newly imported stages to the map\n $this->mapExternalStage($stage);\n\n return $stage;\n }\n\n /**\n * Attach a stage to a default business process.\n * This method is used only in Zoho implementation\n * where both supportsPipelines and supportsPipelines are false\n */\n public function syncBusinessProcessStages(int $stageId): void\n {\n /** @var StageRepository $stageRepository */\n $stageRepository = app(StageRepository::class);\n $processName = 'DefaultOpportunityProcess';\n $data = [\n 'team_id' => $this->team->getId(),\n 'name' => $processName,\n 'type' => Stage::TYPE_OPPORTUNITY,\n 'is_selectable' => true,\n ];\n\n $businessProcess = $stageRepository->findOrCreateBusinessProcess(\n $this->config,\n $processName,\n $data\n );\n\n $businessProcess->stages()->attach($stageId);\n }\n\n /**\n * bool $matchFromOtherCrm\n * When inserting a deal match try to match it to an existing from other CRM within the same team.\n * - This parameter is intended to be manually used only. It will help with\n * matching older opportunities if the team is transitioning from one CRM provider to another.\n */\n private function upsertOpportunity(DTO\\Opportunity $opportunityDto, bool $matchFromOtherCrm = false): ?Opportunity\n {\n $this->logger->info('[integration-app] Importing opportunity', [\n 'crm_provider_id' => $opportunityDto->externalId,\n 'team_id' => $this->team->getId(),\n ]);\n\n if ($this->config === null) {\n $this->logger->warning('[integration-app] Opportunity missing config');\n\n return null;\n }\n\n $stageId = $this->findOpportunityStageId(\n externalStageId: $opportunityDto->stageId,\n stageName: $opportunityDto->stageName\n );\n\n // temporary detect memory usage\n $this->logger->info('[integration-app] Stage ID', [\n 'memory_usage' => memory_get_usage(),\n 'memory_real_usage' => memory_get_usage(true),\n 'crm_provider_id' => $opportunityDto->externalId,\n 'stage_id' => $stageId,\n ]);\n\n $accountId = $this->findAccountId(\n pivotEntityId: $opportunityDto->externalId,\n externalAccountId: $opportunityDto->accountId,\n externalContactId: $opportunityDto->contactId,\n );\n\n $this->logger->info('[integration-app] Account ID', [\n 'memory_usage' => memory_get_usage(),\n 'memory_real_usage' => memory_get_usage(true),\n 'crm_provider_id' => $opportunityDto->externalId,\n 'account_id' => $accountId,\n ]);\n\n if ($stageId === null || $accountId === null) {\n $this->logger->warning('[integration-app] Opportunity missing data', [\n 'stageId' => $stageId,\n 'accountId' => $accountId,\n 'externalId' => $opportunityDto->externalId,\n ]);\n\n return null;\n }\n\n $userId = $this->findMappedUserId(externalUserId: $opportunityDto->ownerId);\n\n $data = [\n 'crm_provider_id' => $opportunityDto->externalId,\n 'team_id' => $this->team->getId(),\n 'account_id' => $accountId,\n 'user_id' => $userId,\n 'owner_id' => $opportunityDto->ownerId,\n 'name' => mb_strimwidth($opportunityDto->name, 0, 128),\n 'value' => $opportunityDto->amount,\n 'currency_code' => CurrencyFormatter::formatCode($this->getCurrencyIso($opportunityDto)),\n 'close_date' => $opportunityDto->closeDate,\n 'is_closed' => $opportunityDto->closed,\n 'is_won' => $opportunityDto->won,\n 'stage_id' => $stageId,\n 'record_type_id' => null,\n 'remotely_created_at' => $opportunityDto->createdAt,\n 'probability' => $opportunityDto->probability,\n ];\n\n /** @var CrmEntityRepository $crmEntityRepo */\n $crmEntityRepo = app(CrmEntityRepository::class);\n $opportunity = $crmEntityRepo->importOpportunity(\n $this->config,\n $data,\n $matchFromOtherCrm,\n $opportunityDto->name,\n );\n\n // Import external fields into crm_field_data if present\n $crmFields = $this->getOpportunitySyncableFields();\n $this->importOpportunityFieldData($opportunityDto, $crmFields, $opportunity->getId());\n\n if ($opportunityDto->deleted === true) {\n $opportunity->delete();\n\n return $opportunity;\n }\n\n if ($opportunity->wasRecentlyCreated) {\n MatchActivitiesToNewOpportunity::dispatch($opportunity->getId());\n }\n\n return $opportunity;\n }\n\n private function findOpportunityStageId(?string $externalStageId, ?string $stageName): ?int\n {\n $stageId = null;\n\n if ($this->editionConfig->supportsStages()) {\n $stageId = $this->findMappedStageId(externalStageId: $externalStageId, type: Stage::TYPE_OPPORTUNITY);\n\n if ($stageId === null) {\n $stageId = $this->importStages(types: [Stage::TYPE_OPPORTUNITY], missingStageName: $stageName)?->id;\n }\n }\n\n if ($stageId === null && $stageName !== null) {\n $stageId = $this->syncStageByNameOnly(\n configuration: $this->config,\n stageName: $stageName,\n type: Stage::TYPE_OPPORTUNITY\n )?->id;\n }\n\n return $stageId;\n }\n\n private function importOpportunityFieldData(\n DTO\\Opportunity $opportunityDto,\n array $crmFields,\n int $opportunityId\n ): void {\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n /** @var FieldDataRepository $fieldDataRepository */\n $fieldDataRepository = app(FieldDataRepository::class);\n\n foreach ($crmFields as $crmField) {\n if (! property_exists($opportunityDto, $crmField)) {\n continue;\n }\n\n if ($opportunityDto->{$crmField} === null) {\n continue;\n }\n\n $field = $fieldRepository->findFieldByCrmIdAndObjectType(\n $this->config,\n $crmField,\n Field::OBJECT_OPPORTUNITY\n );\n\n if (! $field instanceof Field) {\n $this->logger->info('Field not found', [\n 'field' => $crmField,\n 'config' => $this->config->getId(),\n ]);\n\n continue;\n }\n\n $entities = $field->getEntities();\n if ($entities->isEmpty()) {\n $this->logger->info('Field has no entities', [\n 'field' => $crmField,\n 'config' => $this->config->getId(),\n ]);\n\n continue;\n }\n\n if ($entities->count() > 1) {\n $this->logger->info('Field has multiple entities', [\n 'field' => $crmField,\n 'config' => $this->config->getId(),\n ]);\n\n continue;\n }\n\n /** @var LayoutEntity|null $entity */\n $entity = $entities->first();\n if (! $entity instanceof LayoutEntity) {\n continue;\n }\n\n $value = (string) $opportunityDto->{$crmField};\n\n $fieldDataRepository->updateOrCreateFieldData(\n $entity,\n $opportunityId,\n $value,\n );\n }\n }\n\n private function getCurrencyIso(DTO\\Opportunity $opportunityDto): ?string\n {\n if ($opportunityDto->currencyIso !== null) {\n return $opportunityDto->currencyIso;\n }\n\n // Fallback to billing currency\n return $this->config->getDefaultCurrency();\n }\n\n /**\n * Some CRM providers do not support listing all stages.\n * Additionally, they may not even supply us with a stage ID when the stage is supplied as a property of the deal.\n * In that case, we will usually have only a stage name.\n * In order to import such stages only once, we will slugify them and produce \"external ID\" on our own.\n */\n private function syncStageByNameOnly(Configuration $configuration, string $stageName, ?string $type = null): ?Stage\n {\n // @TEMP For testing purposes only!!!\n // Revert when we find suitable way to fetch the stage\n /** @var CrmEntityRepository $crmEntityRepo */\n $crmEntityRepo = app(CrmEntityRepository::class);\n $stage = $crmEntityRepo->getStageForName($configuration, $stageName, $type);\n if ($stage !== null) {\n return $stage;\n }\n\n // if there is other legitimate way to fetch the stage skip.\n if ($this->editionConfig->supportsPipelines() ||\n $this->editionConfig->supportsStages()\n ) {\n return null;\n }\n\n /** @var CrmEntityRepository $crmEntityRepo */\n $crmEntityRepo = app(CrmEntityRepository::class);\n $stage = $crmEntityRepo->getStageForName($configuration, $stageName, $type);\n\n // Create the stage if it does not exist already\n if ($stage === null) {\n $stageDto = new DTO\\EntityStage();\n $stageDto->externalId = $stageName;\n $stageDto->masterLabel = Str::slug($stageName);\n $stageDto->name = $stageName;\n\n $stageDto->type = $type;\n\n $stage = $this->importStage($stageDto);\n\n if ($type === Stage::TYPE_OPPORTUNITY) {\n $this->syncBusinessProcessStages($stage->getId());\n }\n }\n\n return $stage;\n }\n\n private function findAccountId(\n string $pivotEntityId,\n ?string $externalAccountId = null,\n ?string $externalContactId = null,\n bool $skipAccountSync = false,\n ): ?int {\n $accountId = $this->findMappedAccountId(\n pivotEntityId: $pivotEntityId,\n externalAccountId: $externalAccountId,\n skipAccountSync: $skipAccountSync,\n );\n\n if ($accountId !== null) {\n return $accountId;\n }\n\n /**\n * The deal probably does not have an Account assigned.\n * In order to not break the existing import, we will try to find a contact\n * and create an Account with the same data.\n */\n if (! empty($externalContactId)) {\n // In rare cases the contact's external id matches our account id, whe :(\n $this->logger->info('[integration-app] fallback Account', ['contact_id' => $externalContactId]);\n\n $accountId = $this->findMappedAccountId(\n pivotEntityId: $pivotEntityId,\n externalAccountId: $externalContactId,\n skipAccountSync: true,\n );\n\n if ($accountId !== null) {\n return $accountId;\n }\n\n $this->logger->info('[integration-app] create Account from Contact', ['contact_id' => $externalContactId]);\n $crmEntityRepo = app(CrmEntityRepository::class);\n\n $contact = $crmEntityRepo->findContactByExternalId($this->config, $externalContactId);\n if ($contact !== null) {\n return $this->createInternalAccountFromContact($contact)->getId();\n }\n }\n\n return null;\n }\n\n private function createInternalAccountFromContact(Contact $contact): Account\n {\n $this->logger->info('[integration-app] Create internal account from contact', [\n 'team_id' => $this->team?->getId(),\n 'contact_id' => $contact->getId(),\n 'crm_provider_id' => $contact->getCrmProviderId(),\n ]);\n\n $data = [\n 'crm_configuration_id' => $this->config->getId(),\n 'team_id' => $this->config->getTeamId(),\n 'crm_provider_id' => $contact->getCrmProviderId(),\n 'user_id' => $contact->getUserId(),\n 'owner_id' => $contact->getOwnerId(),\n 'name' => $contact->getName(),\n 'phone' => $contact->getPhone(),\n 'country_code' => $contact->getCountryCode(),\n 'remotely_created_at' => $contact->getRemotelyCreatedAt(),\n 'is_internal' => 1,\n ];\n\n /** @var CrmEntityRepository $crmEntityRepo */\n $crmEntityRepo = app(CrmEntityRepository::class);\n $account = $crmEntityRepo->importAccount($this->config, $data);\n\n if ($contact->account_id === null) {\n $contact->account_id = $account->getId();\n $contact->save();\n }\n\n $this->mapExternalAccount($account);\n\n return $account;\n }\n\n private function batchSyncContacts(array $externalContactIds): void\n {\n $this->logger->info('[integration-app] Syncing batch contacts', [\n 'batch_contacts' => implode(',', $externalContactIds),\n 'team_id' => $this->team?->getId(),\n ]);\n\n /** IntegrationApp allows up to 100 IDs passed as a batch. */\n $chunkedContacts = array_chunk($externalContactIds, self::CHUNK_SIZE);\n foreach ($chunkedContacts as $contactGroup) {\n /** @var DTO\\Contact[] $pageResultData */\n foreach ($this->client->getBatchContactsById($contactGroup) as $pageResultData) {\n $externalAccounts = [];\n foreach ($pageResultData as $eachRecord) {\n $externalAccounts[] = $eachRecord->accountId ?? null;\n }\n\n $missingAccounts = $this->identifyMissingAccounts($externalAccounts);\n if (! empty($missingAccounts)) {\n $this->batchSyncAccounts($missingAccounts);\n }\n\n foreach ($pageResultData as $eachRecord) {\n $this->importContact($eachRecord);\n }\n }\n }\n }\n\n private function batchSyncAccounts(array $externalAccountIds): void\n {\n $this->logger->info('[integration-app] Syncing batch accounts', [\n 'batch_contacts' => implode(',', $externalAccountIds),\n 'team_id' => $this->team?->getId(),\n ]);\n\n /** IntegrationApp allows up to 100 IDs passed as a batch. */\n $chunkedAccounts = array_chunk($externalAccountIds, self::CHUNK_SIZE);\n foreach ($chunkedAccounts as $accountGroup) {\n /** @var DTO\\Account[] $pageResultData */\n foreach ($this->client->getBatchAccountsById($accountGroup) as $pageResultData) {\n foreach ($pageResultData as $eachRecord) {\n $this->importAccount($eachRecord);\n }\n }\n }\n }\n\n /**\n * Identify all contacts Ids, that are not found in our database.\n * Scoped to the current batch so memory and query cost scale with batch size,\n * not with tenant size.\n *\n * @param array<?string> $contacts\n *\n * @return list<string>\n */\n private function identifyMissingContacts(array $contacts): array\n {\n $wanted = array_values(array_unique(array_filter($contacts)));\n if ($wanted === []) {\n return [];\n }\n\n /** @var CrmEntityRepository $crmEntityRepo */\n $crmEntityRepo = app(CrmEntityRepository::class);\n $existing = $crmEntityRepo->getExistingContactCrmIds($this->config, $wanted);\n\n return array_values(array_diff($wanted, $existing));\n }\n\n /**\n * Identify all account Ids, that are not found in our database.\n * Scoped to the current batch so memory and query cost scale with batch size,\n * not with tenant size.\n *\n * @param array<?string> $accounts\n *\n * @return list<string>\n */\n private function identifyMissingAccounts(array $accounts): array\n {\n $wanted = array_values(array_unique(array_filter($accounts)));\n if ($wanted === []) {\n return [];\n }\n\n /** @var CrmEntityRepository $crmEntityRepo */\n $crmEntityRepo = app(CrmEntityRepository::class);\n $existing = $crmEntityRepo->getExistingAccountCrmIds($this->config, $wanted);\n\n return array_values(array_diff($wanted, $existing));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.011968086,"top":0.047885075,"width":0.024268618,"height":0.024740623},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"app ~/jiminny/app","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".circleci","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".cursor","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".github","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".sonarlint","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".vscode, folder","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".windsurf","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"app, sources root","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Actions","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Component","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Acl","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActionItems, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Activity, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActivityAnalytics","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActivitySearch","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiActivityType, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiAutomation, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiCallScoring, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskAnything","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Dtos","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Events","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskAnythingPromptService.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"HistoryService.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskJiminnyAi","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AWS","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BillingManagement","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Cache","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CoachingFeedback","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Country, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CustomerApi, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Database, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Datadog, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DateTime, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DealInsights, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DealRisks","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ElasticSearch","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Eloquent","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Encoding","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Encryption","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ES","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Faker","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FeatureFlags","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FFMpeg","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FileSystem","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Gecko","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Gong","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"GuzzleHttp","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"KeyPoints","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Kiosk","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"LanguageDetection","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"LiveFeed","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Locks","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Math","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MediaPipeline","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MeetingBot","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MobileSettings, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Model, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Notification, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Nudge","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ParagraphBreaker","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ParticipantSpeech","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PartitionedCookie","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PlaybackPage","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Playlist","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Prophet","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ProphetAi, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ProsperWorks","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Queue","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Job","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"RateLimitAware.php, abstract class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"RateLimitAwareWrapper.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BotsQueueConstants.php","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Constants.php","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ProcessingQueueConstants.php","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Router, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Saml2","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SCIM","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Seeder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Sentry","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Serializer","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Settings","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Sidekick","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Slack","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"TeamInsights, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"TimeMemoryMapper, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Transcription","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"TranscriptionSummary","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Twilio","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Uploader","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"UrlGenerator","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Utility","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Exceptions","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Service","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BaseRateLimiter.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"EfficientJsonParser.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ProviderRateLimiter.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"RateLimiterInstance.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Uuid","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Waveform","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Webhooks","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Workflow","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Configuration","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Console, folder","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Commands","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Activities","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Analytics","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Calendars","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Crm","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Hubspot","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IntegrationApp","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Traits","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AddLayoutEntities.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AutologDelayedCommand.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BullhornCommandAbstract.php, abstract class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BullhornPingCommand.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BullhornSearchCommand.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BullhornSessionCommand.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CheckActivityLoggableCommand.php, final class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CleanDuplicateFieldDataCommand.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FullSyncOpportunityCommand.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"LogActivitiesCommand.php, final class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ManageSyncStrategyCommand.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MatchCrmObjectsCommand.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MatchOpportunityActivitiesCommand.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MigrateProvider.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ProcessHubspotObjectsSyncBatches.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PurgeDeletedOpportunitiesCommand.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ResetGovernorLimits.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SendNotLogged.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SetupActivityTypeForFollowUp.php, final class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SetupCloseCrm.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SetupCopperCrm.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SetupCrmCommand.php, abstract class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SetupLayouts.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncAccount.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncContact.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncFieldMetadata.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncHubspotActiveDeals.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncHubspotObjects.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncLead.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncObjects.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncOpportunitiesMissingFieldDataCommand.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncOpportunity.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncProfileMetadata.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncTeamMetadata.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"UpdateOpportunitySpecifications.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DealInsights","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Dev","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AddRateLimitCommand.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FixHubSpotTokens.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FixMissMatchedCrmActivitiesCommand.php, final class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ImportCallsCommand.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MonitorSocialAccountsState.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Dialers","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DTOs","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Elasticsearch","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"EngagementStats","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"GeckoExport","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Livestream","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Mailboxes","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Migrate","depth":10,"on_screen":false,"role_description":"text"}]...
|
-8041922121792796695
|
4110884608029145632
|
visual_change
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
Analyzing…
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\IntegrationApp\ServiceTraits;
use Carbon\Carbon;
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\Exception\RequestException;
use Illuminate\Support\Str;
use Jiminny\Events\Activities\Crm\LeadConverted;
use Jiminny\Models\Contact;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\LayoutEntity;
use Jiminny\Models\Lead;
use Jiminny\Models\Opportunity;
use Jiminny\Models\Stage;
use Jiminny\Models\Team;
use Jiminny\Models\Account;
use Jiminny\Jobs\Crm\MatchActivitiesToNewOpportunity;
use Jiminny\Repositories\Crm\CrmEntityRepository;
use Jiminny\Repositories\Crm\FieldDataRepository;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Repositories\Crm\StageRepository;
use Jiminny\Services\Crm\IntegrationApp\Config\IntegrationConfigInterface as IntegrationConfig;
use Jiminny\Services\Crm\IntegrationApp\DTO;
use Jiminny\Services\Crm\IntegrationApp\DataClient;
use Jiminny\Services\Crm\OpportunitySyncStrategyResolver;
use Jiminny\Utils\CurrencyFormatter;
use Psr\Log\LoggerInterface;
/**
* This trait follows closely the contract SyncCrmEntitiesInterface
*/
trait SyncCrmEntitiesTrait
{
use ExternalMapsTrait;
private const int CHUNK_SIZE = 100;
public ?Team $team = null;
public ?Configuration $config;
public ?IntegrationConfig $editionConfig;
protected LoggerInterface $logger;
/**
* @var DataClient
*/
protected $client;
public function syncAllAccounts(): int
{
$count = 0;
foreach ($this->client->getAllAccounts() as $eachAccount) {
$this->importAccount($eachAccount);
$count++;
}
return $count;
}
public function syncAccounts(Carbon $since, ?Carbon $to = null): int
{
$count = 0;
$this->logger->info('[integration-app] Syncing accounts', [
'since' => $since,
'to' => $to,
'team_id' => $this->team?->getId(),
]);
$params = [
'since' => $since,
'to' => $to,
];
/** @var DTO\Account $eachAccount*/
foreach ($this->client->getFilteredAccounts($params) as $eachAccount) {
$this->importAccount($eachAccount);
$count++;
}
$this->logger->info('[integration-app] Syncing accounts finished successfully', [
'since' => $since,
'to' => $to,
'team_id' => $this->team?->getId(),
]);
return $count;
}
public function syncAccount(string $crmId): ?Account
{
try {
$accountDto = $this->client->getSingleAccount($crmId);
if ($accountDto === null) {
return null;
}
return $this->importAccount($accountDto);
} catch (RequestException) {
return null;
}
}
private function importAccount(DTO\Account $accountDto): Account
{
/** @var CrmEntityRepository $crmEntityRepo */
$crmEntityRepo = app(CrmEntityRepository::class);
$data = [
'crm_provider_id' => $accountDto->externalId,
'user_id' => $this->findMappedUserId($accountDto->ownerId),
'owner_id' => $accountDto->ownerId,
'name' => mb_substr($accountDto->name, 0, 191),
'phone' => $accountDto->phone !== null ? mb_substr($accountDto->phone, 0, 25) : null,
'industry' => $accountDto->industry !== null ? mb_substr($accountDto->industry, 0, 191) : null,
'domain' => $accountDto->websiteUrl !== null ? mb_substr($accountDto->websiteUrl, 0, 191) : null,
'country_code' => $accountDto->countryCode,
'remotely_created_at' => $accountDto->createdAt,
];
$this->logger->info('[integration-app] Importing account', [
'crm_provider_id' => $accountDto->externalId,
'team_id' => $this->team?->getId(),
]);
$account = $crmEntityRepo->importAccount($this->getConfiguration(), $data);
$this->mapExternalAccount($account);
return $account;
}
// Sync multiple records.
public function syncAllContacts(): int
{
$count = 0;
foreach ($this->client->getAllContacts() as $eachContact) {
// import contacts here
$this->importContact(contactDto: $eachContact);
$count++;
}
return $count;
}
public function syncContacts(Carbon $since, ?Carbon $to = null): int
{
$count = 0;
$this->logger->info('[integration-app] Syncing contacts', [
'since' => $since,
'to' => $to,
'team_id' => $this->team?->getId(),
]);
$params = [
'since' => $since,
'to' => $to,
];
foreach ($this->client->getFilteredContacts($params) as $eachContact) {
$this->importContact($eachContact);
$count++;
}
$this->logger->info('[integration-app] Syncing contacts finished successfully', [
'since' => $since,
'to' => $to,
'team_id' => $this->team?->getId(),
]);
return $count;
}
// Sync single records.
public function syncContact(string $crmId): ?Contact
{
try {
$contactRecord = $this->client->getSingleContact($crmId);
if ($contactRecord === null) {
return null;
}
return $this->importContact($contactRecord);
} catch (RequestException) {
return null;
}
}
private function importContact(DTO\Contact $contactDto): ?Contact
{
$createInternalAccount = false;
/** @var CrmEntityRepository $crmEntityRepo */
$crmEntityRepo = app(CrmEntityRepository::class);
$accountId = $this->findMappedAccountId(
pivotEntityId: $contactDto->externalId,
externalAccountId: $contactDto->accountId,
);
$userId = $this->findMappedUserId($contactDto->ownerId);
if ($accountId === null) {
$this->logger->info('[integration-app] Importing contact, but related account cannot be found', [
'crm_provider_id' => $contactDto->externalId,
'raw_account_id' => $contactDto->accountId,
'name' => $contactDto->fullName,
'user_id' => $userId,
]);
$createInternalAccount = true;
}
$data = [
'user_id' => $userId,
'account_id' => $accountId,
'crm_provider_id' => $contactDto->externalId,
'owner_id' => $contactDto->ownerId,
'name' => $contactDto->fullName !== null ? mb_substr($contactDto->fullName, 0, 100) : null,
'title' => $contactDto->title !== null ? mb_substr($contactDto->title, 0, 100) : null,
'email' => $contactDto->primaryEmail !== null ? mb_substr($contactDto->primaryEmail, 0, 191) : null,
'phone' => $contactDto->phone !== null ? mb_substr($contactDto->phone, 0, 25) : null,
'mobile_phone' => $contactDto->mobilePhone !== null ? mb_substr($contactDto->mobilePhone, 0, 25) : null,
'country_code' => $contactDto->countryCode !== null ? mb_substr($contactDto->countryCode, 0, 2) : null,
'remotely_created_at' => $contactDto->createdAt,
'photo_path' => '',
];
$this->logger->info('[integration-app] Importing contact', [
'crm_provider_id' => $contactDto->externalId,
'team_id' => $this->team?->getId(),
]);
$contact = $crmEntityRepo->importContact($this->getConfiguration(), $data);
$this->mapExternalContact($contact);
if ($createInternalAccount) {
$this->createInternalAccountFromContact($contact)->getId();
}
return $contact;
}
/**
* @param bool $matchFromOtherCrm - This parameter is intended to be manually used. It will help with
* matching older opportunities if the team is transitioning from one CRM provider to another.
*/
public function syncAllOpportunities(bool $matchFromOtherCrm = false): int
{
$count = 0;
foreach ($this->client->getAllOpportunities() as $eachDeal) {
$this->upsertOpportunity($eachDeal, $matchFromOtherCrm);
$count++;
}
return $count;
}
public function syncOpportunities(array $parameters, ?string $strategy = null): int
{
$parameters['strategy'] = $strategy ?? OpportunitySyncStrategyResolver::LAST_MODIFIED_SYNC_OPPORTUNITY_STRATEGY;
$count = 0;
$this->logger->info('[integration-app] Syncing opportunities', [
'parameters' => $parameters,
'team_id' => $this->team?->getId(),
]);
/** @var DTO\Opportunity[] $pageResultData */
foreach ($this->client->getFilteredOpportunities($parameters) as $pageResultData) {
$externalAccounts = [];
$externalContacts = [];
foreach ($pageResultData as $eachRecord) {
$externalAccounts[] = $eachRecord->accountId ?? null;
$externalContacts[] = $eachRecord->contactId ?? null;
}
// Import missing contacts and account as early as possible
$missingContacts = $this->identifyMissingContacts($externalContacts);
if (! empty($missingContacts)) {
$this->batchSyncContacts($missingContacts);
}
$missingAccounts = $this->identifyMissingAccounts($externalAccounts);
if (! empty($missingAccounts)) {
$this->batchSyncAccounts($missingAccounts);
}
foreach ($pageResultData as $eachRecord) {
$this->upsertOpportunity($eachRecord);
$count++;
}
}
$this->logger->info('[integration-app] Syncing opportunities finished successfully', [
'parameters' => $parameters,
'team_id' => $this->team?->getId(),
]);
return $count;
}
public function syncOpportunity(string $crmId): ?Opportunity
{
try {
$opportunityRecord = $this->client->getSingleOpportunity($crmId);
if ($opportunityRecord === null) {
return null;
}
return $this->upsertOpportunity($opportunityRecord);
} catch (RequestException) {
return null;
}
}
public function syncAllLeads(): int
{
if (isset($this->config->getSettings()['lead_sync_disabled'])) {
$this->logger->info('[integration-app] Syncing leads disabled for the client', [
'team_id' => $this->team?->getId(),
]);
return 0;
}
$count = 0;
foreach ($this->client->getAllLeads() as $eachLead) {
$this->importLead($eachLead);
$count++;
}
return $count;
}
public function syncLeads(Carbon $since, ?Carbon $to = null, ?string $crmProfileId = null): int
{
if (isset($this->config->getSettings()['lead_sync_disabled'])) {
$this->logger->info('[integration-app] Syncing leads disabled for the client', [
'team_id' => $this->team?->getId(),
'since' => $since,
'to' => $to,
'crm_profile_id' => $crmProfileId,
]);
return 0;
}
$count = 0;
$this->logger->info('[integration-app] Syncing leads', [
'since' => $since,
'to' => $to,
'crm_profile_id' => $crmProfileId,
'team_id' => $this->team?->getId(),
]);
$filterData = [
'since' => $since,
'to' => $to,
'crm_profile_id' => $crmProfileId,
'converted' => 'both',
];
foreach ($this->client->getFilteredLeads($filterData) as $eachLead) {
$this->importLead($eachLead);
$count++;
}
$this->logger->info('[integration-app] Syncing leads finished successfully', [
'since' => $since,
'to' => $to,
'team_id' => $this->team?->getId(),
]);
return $count;
}
public function syncLead(string $crmId): ?Lead
{
if (isset($this->config->getSettings()['lead_sync_disabled'])) {
$this->logger->info('[integration-app] Syncing leads disabled for the client', [
'team_id' => $this->team?->getId(),
'crm_id' => $crmId,
]);
return null;
}
try {
$leadRecord = $this->client->getSingleAndConvertLead($crmId);
if ($leadRecord === null) {
return null;
}
return $this->importLead($leadRecord);
} catch (RequestException) {
return null;
}
}
private function importLead(DTO\Lead $leadDto): ?Lead
{
/** @var CrmEntityRepository $crmEntityRepo */
$crmEntityRepo = app(CrmEntityRepository::class);
$userId = $this->findMappedUserId($leadDto->ownerId);
$stage = null;
if ($this->editionConfig->supportsStages()) {
// Get the current stage.
$stage = $crmEntityRepo->getStageForName(
configuration: $this->config,
name: $leadDto->status,
type: Stage::TYPE_LEAD
);
}
if ($stage === null && ! empty($leadDto->status)) {
// Try to sync and import the lead stage by name only
$stage = $this->syncStageByNameOnly($this->config, $leadDto->status, Stage::TYPE_LEAD);
}
$stageId = $stage?->id;
$leadData = [
'team_id' => $this->team->getId(),
'crm_configuration_id' => $this->config->getId(),
'crm_provider_id' => $leadDto->externalId,
'name' => $leadDto->fullName,
'company' => $leadDto->companyName,
'owner_id' => $leadDto->ownerId,
'user_id' => $userId,
'stage_id' => $stageId,
'email' => $leadDto->primaryEmail,
'phone' => $leadDto->primaryPhone,
'mobile_phone' => $leadDto->secondaryPhone,
'title' => $leadDto->jobTitle,
'remotely_created_at' => $leadDto->createdAt,
];
$convertedLeadData = $this->processConvertedLead($crmEntityRepo, $leadDto);
$leadData = array_merge($leadData, $convertedLeadData);
$this->logger->info('[integration-app] Importing lead', [
'crm_provider_id' => $leadDto->externalId,
'name' => $leadDto->primaryEmail,
'team_id' => $this->team?->getId(),
]);
$lead = $crmEntityRepo->importLead($this->config, $leadData);
$this->dispatchLeadConvertedEvent($lead);
return $lead;
}
private function processConvertedLead(CrmEntityRepository $crmEntityRepo, DTO\Lead $leadDto): array
{
if (! $leadDto->isConverted()) {
return [];
}
$leadData = [
'converted_at' => $leadDto->getConvertedAt(),
];
$this->decorateWithConvertedContact($crmEntityRepo, $leadDto, $leadData);
$this->decorateWithConvertedAccount($crmEntityRepo, $leadDto, $leadData);
$this->decorateWithConvertedOpportunity($crmEntityRepo, $leadDto, $leadData);
return $leadData;
}
private function dispatchLeadConvertedEvent(Lead $lead): void
{
if ($lead->wasChanged('converted_at') && $lead->getConvertedAt() !== null) {
event(new LeadConverted($lead));
}
}
private function decorateWithConvertedContact(
CrmEntityRepository $crmEntityRepo,
DTO\Lead $leadDto,
array &$leadData
): void {
if ($leadDto->getConvertedContactId() !== null) {
$convertedContact = $crmEntityRepo->findContactByExternalId(
$this->config,
$leadDto->getConvertedContactId()
);
if ($convertedContact === null) {
try {
$convertedContact = $this->syncContact($leadDto->getConvertedContactId());
} catch (\Exception $exception) {
$this->logger->error('[integration-app] Error syncing converted contact', [
'lead_id' => $leadDto->getExternalId(),
'crm_provider_id' => $leadDto->getConvertedContactId(),
'error' => $exception->getMessage(),
]);
}
}
$leadData['converted_contact_id'] = $convertedContact?->getId();
}
}
private function decorateWithConvertedAccount(
CrmEntityRepository $crmEntityRepo,
DTO\Lead $leadDto,
array &$leadData
): void {
if ($leadDto->getConvertedAccountId() !== null) {
$convertedAccount = $crmEntityRepo->findAccountByExternalId(
$this->config,
$leadDto->getConvertedAccountId()
);
if ($convertedAccount === null) {
try {
$convertedAccount = $this->syncAccount($leadDto->getConvertedAccountId());
} catch (\Exception $exception) {
$this->logger->error('[integration-app] Error syncing converted account', [
'lead_id' => $leadDto->getExternalId(),
'crm_provider_id' => $leadDto->getConvertedAccountId(),
'error' => $exception->getMessage(),
]);
}
}
$leadData['converted_account_id'] = $convertedAccount?->getId();
}
}
private function decorateWithConvertedOpportunity(
CrmEntityRepository $crmEntityRepo,
DTO\Lead $leadDto,
array &$leadData
): void {
if ($leadDto->getConvertedOpportunityId() !== null) {
$convertedOpportunity = $crmEntityRepo->findOpportunityByExternalId(
$this->config,
$leadDto->getConvertedOpportunityId()
);
if ($convertedOpportunity === null) {
try {
$convertedOpportunity = $this->syncOpportunity($leadDto->getConvertedOpportunityId());
} catch (\Exception $exception) {
$this->logger->error('[integration-app] Error syncing converted opportunity', [
'lead_id' => $leadDto->getExternalId(),
'crm_provider_id' => $leadDto->getConvertedOpportunityId(),
'error' => $exception->getMessage(),
]);
}
}
$leadData['converted_opportunity_id'] = $convertedOpportunity?->getId();
}
}
/**
* @throws GuzzleException
*/
public function importStages(?array $types = null, ?string $missingStageName = null): ?Stage
{
if (! $this->editionConfig->supportsStages()) {
return null;
}
$missingStage = null;
$stagesCollection = $this->client->getAllDealsStages();
foreach ($stagesCollection as $eachStage) {
$stage = $this->importStage($eachStage);
if ($stage->getName() === $missingStageName) {
$missingStage = $stage;
}
}
return $missingStage;
}
private function importStage(DTO\EntityStage $stageDto): Stage
{
/** @var CrmEntityRepository $crmEntityRepo */
$crmEntityRepo = app(CrmEntityRepository::class);
$objectType = $stageDto->type ?? Stage::TYPE_OPPORTUNITY;
$stageData = [
'crm_provider_id' => $stageDto->externalId,
'name' => mb_strimwidth($stageDto->apiName ?? $stageDto->name, 0, 50),
'label' => mb_strimwidth($stageDto->masterLabel ?? $stageDto->name, 0, 191),
'sequence' => $stageDto->sortOrder ?? 0,
'probability' => $stageDto->defaultProbability ?? null,
'is_selectable' => $stageDto->isActive ?? 0,
'type' => $objectType,
];
$this->logger->info('[integration-app] Importing stage', [
'crm_provider_id' => $stageDto->externalId,
'name' => $stageDto->name,
'team_id' => $this->team?->getId(),
]);
$stage = $crmEntityRepo->importStage($this->config, $objectType, $stageData);
// Include newly imported stages to the map
$this->mapExternalStage($stage);
return $stage;
}
/**
* Attach a stage to a default business process.
* This method is used only in Zoho implementation
* where both supportsPipelines and supportsPipelines are false
*/
public function syncBusinessProcessStages(int $stageId): void
{
/** @var StageRepository $stageRepository */
$stageRepository = app(StageRepository::class);
$processName = 'DefaultOpportunityProcess';
$data = [
'team_id' => $this->team->getId(),
'name' => $processName,
'type' => Stage::TYPE_OPPORTUNITY,
'is_selectable' => true,
];
$businessProcess = $stageRepository->findOrCreateBusinessProcess(
$this->config,
$processName,
$data
);
$businessProcess->stages()->attach($stageId);
}
/**
* bool $matchFromOtherCrm
* When inserting a deal match try to match it to an existing from other CRM within the same team.
* - This parameter is intended to be manually used only. It will help with
* matching older opportunities if the team is transitioning from one CRM provider to another.
*/
private function upsertOpportunity(DTO\Opportunity $opportunityDto, bool $matchFromOtherCrm = false): ?Opportunity
{
$this->logger->info('[integration-app] Importing opportunity', [
'crm_provider_id' => $opportunityDto->externalId,
'team_id' => $this->team->getId(),
]);
if ($this->config === null) {
$this->logger->warning('[integration-app] Opportunity missing config');
return null;
}
$stageId = $this->findOpportunityStageId(
externalStageId: $opportunityDto->stageId,
stageName: $opportunityDto->stageName
);
// temporary detect memory usage
$this->logger->info('[integration-app] Stage ID', [
'memory_usage' => memory_get_usage(),
'memory_real_usage' => memory_get_usage(true),
'crm_provider_id' => $opportunityDto->externalId,
'stage_id' => $stageId,
]);
$accountId = $this->findAccountId(
pivotEntityId: $opportunityDto->externalId,
externalAccountId: $opportunityDto->accountId,
externalContactId: $opportunityDto->contactId,
);
$this->logger->info('[integration-app] Account ID', [
'memory_usage' => memory_get_usage(),
'memory_real_usage' => memory_get_usage(true),
'crm_provider_id' => $opportunityDto->externalId,
'account_id' => $accountId,
]);
if ($stageId === null || $accountId === null) {
$this->logger->warning('[integration-app] Opportunity missing data', [
'stageId' => $stageId,
'accountId' => $accountId,
'externalId' => $opportunityDto->externalId,
]);
return null;
}
$userId = $this->findMappedUserId(externalUserId: $opportunityDto->ownerId);
$data = [
'crm_provider_id' => $opportunityDto->externalId,
'team_id' => $this->team->getId(),
'account_id' => $accountId,
'user_id' => $userId,
'owner_id' => $opportunityDto->ownerId,
'name' => mb_strimwidth($opportunityDto->name, 0, 128),
'value' => $opportunityDto->amount,
'currency_code' => CurrencyFormatter::formatCode($this->getCurrencyIso($opportunityDto)),
'close_date' => $opportunityDto->closeDate,
'is_closed' => $opportunityDto->closed,
'is_won' => $opportunityDto->won,
'stage_id' => $stageId,
'record_type_id' => null,
'remotely_created_at' => $opportunityDto->createdAt,
'probability' => $opportunityDto->probability,
];
/** @var CrmEntityRepository $crmEntityRepo */
$crmEntityRepo = app(CrmEntityRepository::class);
$opportunity = $crmEntityRepo->importOpportunity(
$this->config,
$data,
$matchFromOtherCrm,
$opportunityDto->name,
);
// Import external fields into crm_field_data if present
$crmFields = $this->getOpportunitySyncableFields();
$this->importOpportunityFieldData($opportunityDto, $crmFields, $opportunity->getId());
if ($opportunityDto->deleted === true) {
$opportunity->delete();
return $opportunity;
}
if ($opportunity->wasRecentlyCreated) {
MatchActivitiesToNewOpportunity::dispatch($opportunity->getId());
}
return $opportunity;
}
private function findOpportunityStageId(?string $externalStageId, ?string $stageName): ?int
{
$stageId = null;
if ($this->editionConfig->supportsStages()) {
$stageId = $this->findMappedStageId(externalStageId: $externalStageId, type: Stage::TYPE_OPPORTUNITY);
if ($stageId === null) {
$stageId = $this->importStages(types: [Stage::TYPE_OPPORTUNITY], missingStageName: $stageName)?->id;
}
}
if ($stageId === null && $stageName !== null) {
$stageId = $this->syncStageByNameOnly(
configuration: $this->config,
stageName: $stageName,
type: Stage::TYPE_OPPORTUNITY
)?->id;
}
return $stageId;
}
private function importOpportunityFieldData(
DTO\Opportunity $opportunityDto,
array $crmFields,
int $opportunityId
): void {
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
/** @var FieldDataRepository $fieldDataRepository */
$fieldDataRepository = app(FieldDataRepository::class);
foreach ($crmFields as $crmField) {
if (! property_exists($opportunityDto, $crmField)) {
continue;
}
if ($opportunityDto->{$crmField} === null) {
continue;
}
$field = $fieldRepository->findFieldByCrmIdAndObjectType(
$this->config,
$crmField,
Field::OBJECT_OPPORTUNITY
);
if (! $field instanceof Field) {
$this->logger->info('Field not found', [
'field' => $crmField,
'config' => $this->config->getId(),
]);
continue;
}
$entities = $field->getEntities();
if ($entities->isEmpty()) {
$this->logger->info('Field has no entities', [
'field' => $crmField,
'config' => $this->config->getId(),
]);
continue;
}
if ($entities->count() > 1) {
$this->logger->info('Field has multiple entities', [
'field' => $crmField,
'config' => $this->config->getId(),
]);
continue;
}
/** @var LayoutEntity|null $entity */
$entity = $entities->first();
if (! $entity instanceof LayoutEntity) {
continue;
}
$value = (string) $opportunityDto->{$crmField};
$fieldDataRepository->updateOrCreateFieldData(
$entity,
$opportunityId,
$value,
);
}
}
private function getCurrencyIso(DTO\Opportunity $opportunityDto): ?string
{
if ($opportunityDto->currencyIso !== null) {
return $opportunityDto->currencyIso;
}
// Fallback to billing currency
return $this->config->getDefaultCurrency();
}
/**
* Some CRM providers do not support listing all stages.
* Additionally, they may not even supply us with a stage ID when the stage is supplied as a property of the deal.
* In that case, we will usually have only a stage name.
* In order to import such stages only once, we will slugify them and produce "external ID" on our own.
*/
private function syncStageByNameOnly(Configuration $configuration, string $stageName, ?string $type = null): ?Stage
{
// @TEMP For testing purposes only!!!
// Revert when we find suitable way to fetch the stage
/** @var CrmEntityRepository $crmEntityRepo */
$crmEntityRepo = app(CrmEntityRepository::class);
$stage = $crmEntityRepo->getStageForName($configuration, $stageName, $type);
if ($stage !== null) {
return $stage;
}
// if there is other legitimate way to fetch the stage skip.
if ($this->editionConfig->supportsPipelines() ||
$this->editionConfig->supportsStages()
) {
return null;
}
/** @var CrmEntityRepository $crmEntityRepo */
$crmEntityRepo = app(CrmEntityRepository::class);
$stage = $crmEntityRepo->getStageForName($configuration, $stageName, $type);
// Create the stage if it does not exist already
if ($stage === null) {
$stageDto = new DTO\EntityStage();
$stageDto->externalId = $stageName;
$stageDto->masterLabel = Str::slug($stageName);
$stageDto->name = $stageName;
$stageDto->type = $type;
$stage = $this->importStage($stageDto);
if ($type === Stage::TYPE_OPPORTUNITY) {
$this->syncBusinessProcessStages($stage->getId());
}
}
return $stage;
}
private function findAccountId(
string $pivotEntityId,
?string $externalAccountId = null,
?string $externalContactId = null,
bool $skipAccountSync = false,
): ?int {
$accountId = $this->findMappedAccountId(
pivotEntityId: $pivotEntityId,
externalAccountId: $externalAccountId,
skipAccountSync: $skipAccountSync,
);
if ($accountId !== null) {
return $accountId;
}
/**
* The deal probably does not have an Account assigned.
* In order to not break the existing import, we will try to find a contact
* and create an Account with the same data.
*/
if (! empty($externalContactId)) {
// In rare cases the contact's external id matches our account id, whe :(
$this->logger->info('[integration-app] fallback Account', ['contact_id' => $externalContactId]);
$accountId = $this->findMappedAccountId(
pivotEntityId: $pivotEntityId,
externalAccountId: $externalContactId,
skipAccountSync: true,
);
if ($accountId !== null) {
return $accountId;
}
$this->logger->info('[integration-app] create Account from Contact', ['contact_id' => $externalContactId]);
$crmEntityRepo = app(CrmEntityRepository::class);
$contact = $crmEntityRepo->findContactByExternalId($this->config, $externalContactId);
if ($contact !== null) {
return $this->createInternalAccountFromContact($contact)->getId();
}
}
return null;
}
private function createInternalAccountFromContact(Contact $contact): Account
{
$this->logger->info('[integration-app] Create internal account from contact', [
'team_id' => $this->team?->getId(),
'contact_id' => $contact->getId(),
'crm_provider_id' => $contact->getCrmProviderId(),
]);
$data = [
'crm_configuration_id' => $this->config->getId(),
'team_id' => $this->config->getTeamId(),
'crm_provider_id' => $contact->getCrmProviderId(),
'user_id' => $contact->getUserId(),
'owner_id' => $contact->getOwnerId(),
'name' => $contact->getName(),
'phone' => $contact->getPhone(),
'country_code' => $contact->getCountryCode(),
'remotely_created_at' => $contact->getRemotelyCreatedAt(),
'is_internal' => 1,
];
/** @var CrmEntityRepository $crmEntityRepo */
$crmEntityRepo = app(CrmEntityRepository::class);
$account = $crmEntityRepo->importAccount($this->config, $data);
if ($contact->account_id === null) {
$contact->account_id = $account->getId();
$contact->save();
}
$this->mapExternalAccount($account);
return $account;
}
private function batchSyncContacts(array $externalContactIds): void
{
$this->logger->info('[integration-app] Syncing batch contacts', [
'batch_contacts' => implode(',', $externalContactIds),
'team_id' => $this->team?->getId(),
]);
/** IntegrationApp allows up to 100 IDs passed as a batch. */
$chunkedContacts = array_chunk($externalContactIds, self::CHUNK_SIZE);
foreach ($chunkedContacts as $contactGroup) {
/** @var DTO\Contact[] $pageResultData */
foreach ($this->client->getBatchContactsById($contactGroup) as $pageResultData) {
$externalAccounts = [];
foreach ($pageResultData as $eachRecord) {
$externalAccounts[] = $eachRecord->accountId ?? null;
}
$missingAccounts = $this->identifyMissingAccounts($externalAccounts);
if (! empty($missingAccounts)) {
$this->batchSyncAccounts($missingAccounts);
}
foreach ($pageResultData as $eachRecord) {
$this->importContact($eachRecord);
}
}
}
}
private function batchSyncAccounts(array $externalAccountIds): void
{
$this->logger->info('[integration-app] Syncing batch accounts', [
'batch_contacts' => implode(',', $externalAccountIds),
'team_id' => $this->team?->getId(),
]);
/** IntegrationApp allows up to 100 IDs passed as a batch. */
$chunkedAccounts = array_chunk($externalAccountIds, self::CHUNK_SIZE);
foreach ($chunkedAccounts as $accountGroup) {
/** @var DTO\Account[] $pageResultData */
foreach ($this->client->getBatchAccountsById($accountGroup) as $pageResultData) {
foreach ($pageResultData as $eachRecord) {
$this->importAccount($eachRecord);
}
}
}
}
/**
* Identify all contacts Ids, that are not found in our database.
* Scoped to the current batch so memory and query cost scale with batch size,
* not with tenant size.
*
* @param array<?string> $contacts
*
* @return list<string>
*/
private function identifyMissingContacts(array $contacts): array
{
$wanted = array_values(array_unique(array_filter($contacts)));
if ($wanted === []) {
return [];
}
/** @var CrmEntityRepository $crmEntityRepo */
$crmEntityRepo = app(CrmEntityRepository::class);
$existing = $crmEntityRepo->getExistingContactCrmIds($this->config, $wanted);
return array_values(array_diff($wanted, $existing));
}
/**
* Identify all account Ids, that are not found in our database.
* Scoped to the current batch so memory and query cost scale with batch size,
* not with tenant size.
*
* @param array<?string> $accounts
*
* @return list<string>
*/
private function identifyMissingAccounts(array $accounts): array
{
$wanted = array_values(array_unique(array_filter($accounts)));
if ($wanted === []) {
return [];
}
/** @var CrmEntityRepository $crmEntityRepo */
$crmEntityRepo = app(CrmEntityRepository::class);
$existing = $crmEntityRepo->getExistingAccountCrmIds($this->config, $wanted);
return array_values(array_diff($wanted, $existing));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode, folder
.windsurf
app, sources root
Actions
Component
Acl
ActionItems, folder
Activity, folder
ActivityAnalytics
ActivitySearch
AiActivityType, folder
AiAutomation, folder
AiCallScoring, folder
AskAnything
Dtos
Events
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi
AWS
BillingManagement
Cache
CoachingFeedback
Country, folder
CustomerApi, folder
Database, folder
Datadog, folder
DateTime, folder
DealInsights, folder
DealRisks
ElasticSearch
Eloquent
Encoding
Encryption
ES
Faker
FeatureFlags
FFMpeg
FileSystem
Gecko
Gong
GuzzleHttp
KeyPoints
Kiosk
LanguageDetection
LiveFeed
Locks
Math
MediaPipeline
MeetingBot
MobileSettings, folder
Model, folder
Notification, folder
Nudge
ParagraphBreaker
ParticipantSpeech
PartitionedCookie
PlaybackPage
Playlist
Prophet
ProphetAi, folder
ProsperWorks
Queue
Job
RateLimitAware.php, abstract class
RateLimitAwareWrapper.php, class
BotsQueueConstants.php
Constants.php
ProcessingQueueConstants.php
Router, folder
Saml2
SCIM
Seeder
Sentry
Serializer
Settings
Sidekick
Slack
TeamInsights, folder
TimeMemoryMapper, folder
Transcription
TranscriptionSummary
Twilio
Uploader
UrlGenerator
Utility
Exceptions
Service
BaseRateLimiter.php, class
EfficientJsonParser.php, class
ProviderRateLimiter.php, class
RateLimiterInstance.php, class
Uuid
Waveform
Webhooks
Workflow
Configuration
Console, folder
Commands
Activities
Analytics
Calendars
Crm
Hubspot
IntegrationApp
Traits
AddLayoutEntities.php, class
AutologDelayedCommand.php, class
BullhornCommandAbstract.php, abstract class
BullhornPingCommand.php, class
BullhornSearchCommand.php, class
BullhornSessionCommand.php, class
CheckActivityLoggableCommand.php, final class
CleanDuplicateFieldDataCommand.php, class
FullSyncOpportunityCommand.php, class
LogActivitiesCommand.php, final class
ManageSyncStrategyCommand.php, class
MatchCrmObjectsCommand.php, class
MatchOpportunityActivitiesCommand.php, class
MigrateProvider.php, class
ProcessHubspotObjectsSyncBatches.php, class
PurgeDeletedOpportunitiesCommand.php, class
ResetGovernorLimits.php, class
SendNotLogged.php, class
SetupActivityTypeForFollowUp.php, final class
SetupCloseCrm.php, class
SetupCopperCrm.php, class
SetupCrmCommand.php, abstract class
SetupLayouts.php, class
SyncAccount.php, class
SyncContact.php, class
SyncFieldMetadata.php, class
SyncHubspotActiveDeals.php, class
SyncHubspotObjects.php, class
SyncLead.php, class
SyncObjects.php, class
SyncOpportunitiesMissingFieldDataCommand.php, class
SyncOpportunity.php, class
SyncProfileMetadata.php, class
SyncTeamMetadata.php, class
UpdateOpportunitySpecifications.php, class
DealInsights
Dev
AddRateLimitCommand.php, class
FixHubSpotTokens.php, class
FixMissMatchedCrmActivitiesCommand.php, final class
ImportCallsCommand.php, class
MonitorSocialAccountsState.php, class
Dialers
DTOs
Elasticsearch
EngagementStats
GeckoExport
Livestream
Mailboxes
Migrate...
|
3065
|
NULL
|
NULL
|
NULL
|
|
3074
|
119
|
43
|
2026-05-07T11:59:21.942996+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-07/1778 /Users/lukas/.screenpipe/data/data/2026-05-07/1778155161942_m1.jpg...
|
PhpStorm
|
faVsco.js – Client.php
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
[2026-05-07 11:59:07] local.INFO: Jiminny\Console\Commands\Command::run Memory usage before starting command {"command":"meeting-bot:schedule-bot","memoryBeforeCommandInMb":62.0,"memoryPeakBeforeCommandInMb":99.727} {"correlation_id":"3cb37764-b6ec-4d4c-85b3-298d24411fec","trace_id":"1387c33f-5f58-4299-a3da-9c3ad7e240fe"}
[2026-05-07 11:59:07] local.INFO: [ScheduleBotCommand] Number of activities to be captured: 0 {"correlation_id":"3cb37764-b6ec-4d4c-85b3-298d24411fec","trace_id":"1387c33f-5f58-4299-a3da-9c3ad7e240fe"}
[2026-05-07 11:59:07] local.INFO: Jiminny\Console\Commands\Command::run Memory usage for command {"command":"meeting-bot:schedule-bot","memoryBeforeCommandInMb":62.0,"memoryAfterCommandInMB":62.0,"memoryPeakBeforeCommandInMb":99.727,"memoryPeakAfterCommandInMB":99.727} {"correlation_id":"3cb37764-b6ec-4d4c-85b3-298d24411fec","trace_id":"1387c33f-5f58-4299-a3da-9c3ad7e240fe"}
[2026-05-07 11:59:10] local.INFO: Jiminny\Console\Commands\Command::run Memory usage before starting command {"command":"dialers:monitor-activities","memoryBeforeCommandInMb":62.0,"memoryPeakBeforeCommandInMb":99.727} {"correlation_id":"997b55b4-ed52-4426-95b2-3d79f48278ae","trace_id":"9a0814b7-e0ae-4f6d-ad98-2979c51e16cb"}
[2026-05-07 11:59:10] local.INFO: Jiminny\Console\Commands\Command::run Memory usage for command {"command":"dialers:monitor-activities","memoryBeforeCommandInMb":62.0,"memoryAfterCommandInMB":62.0,"memoryPeakBeforeCommandInMb":99.727,"memoryPeakAfterCommandInMB":99.727} {"correlation_id":"997b55b4-ed52-4426-95b2-3d79f48278ae","trace_id":"9a0814b7-e0ae-4f6d-ad98-2979c51e16cb"}
[2026-05-07 11:59:13] local.NOTICE: Monitoring start {"correlation_id":"1f069a13-4342-40ed-bf79-1472c9c60637","trace_id":"1c2564a5-1d98-4061-819a-060f3143e672"}
[2026-05-07 11:59:13] local.NOTICE: Monitoring end {"correlation_id":"1f069a13-4342-40ed-bf79-1472c9c60637","trace_id":"1c2564a5-1d98-4061-819a-060f3143e672"}
[2026-05-07 11:59:15] local.INFO: Jiminny\Console\Commands\Command::run Memory usage before starting command {"command":"mailbox:skip-lists:refresh","memoryBeforeCommandInMb":62.0,"memoryPeakBeforeCommandInMb":99.727} {"correlation_id":"92fadd4f-de00-4eae-8e71-26517f0e405c","trace_id":"034b1cf6-05b1-455d-9d58-e7286ec06e25"}
[2026-05-07 11:59:15] local.INFO: Jiminny\Console\Commands\Command::run Memory usage for command {"command":"mailbox:skip-lists:refresh","memoryBeforeCommandInMb":62.0,"memoryAfterCommandInMB":62.0,"memoryPeakBeforeCommandInMb":99.727,"memoryPeakAfterCommandInMB":99.727} {"correlation_id":"92fadd4f-de00-4eae-8e71-26517f0e405c","trace_id":"034b1cf6-05b1-455d-9d58-e7286ec06e25"}
[2026-05-07 11:59:17] local.INFO: Jiminny\Console\Commands\Command::run Memory usage before starting command {"command":"mailbox:batch:process","memoryBeforeCommandInMb":62.0,"memoryPeakBeforeCommandInMb":99.727} {"correlation_id":"2bbdc0e4-afb2-4fa9-bbf7-b67fa2ca32cc","trace_id":"a7cdd06b-a602-49f9-a0f7-24736d4d641a"}
[2026-05-07 11:59:17] local.INFO: [EmailSchedule] STARTING batch process {"host":"docker_lamp_1"} {"correlation_id":"2bbdc0e4-afb2-4fa9-bbf7-b67fa2ca32cc","trace_id":"a7cdd06b-a602-49f9-a0f7-24736d4d641a"}
[2026-05-07 11:59:17] local.INFO: [EmailSchedule] FINISHED batch process {"host":"docker_lamp_1","processed":0} {"correlation_id":"2bbdc0e4-afb2-4fa9-bbf7-b67fa2ca32cc","trace_id":"a7cdd06b-a602-49f9-a0f7-24736d4d641a"}
[2026-05-07 11:59:17] local.INFO: Jiminny\Console\Commands\Command::run Memory usage for command {"command":"mailbox:batch:process","memoryBeforeCommandInMb":62.0,"memoryAfterCommandInMB":62.0,"memoryPeakBeforeCommandInMb":99.727,"memoryPeakAfterCommandInMB":99.727} {"correlation_id":"2bbdc0e4-afb2-4fa9-bbf7-b67fa2ca32cc","trace_id":"a7cdd06b-a602-49f9-a0f7-24736d4d641a"}
Sync Changes
Hide This Notification
Code changed:
Hide
2
60
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot;
use HubSpot\Client\Crm\Deals\ApiException as DealApiException;
use HubSpot\Client\Crm\Contacts\ApiException as ContactApiException;
use HubSpot\Client\Crm\Companies\ApiException as CompanyApiException;
use HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectWithAssociations as ContactsWithAssociations;
use HubSpot\Client\Crm\Companies\Model\SimplePublicObjectWithAssociations as CompaniesWithAssociations;
use HubSpot\Client\Crm\Deals\Model\SimplePublicObjectWithAssociations as DealWithAssociations;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectInput;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectWithAssociations as ObjectWithAssociations;
use HubSpot\Client\Crm\Pipelines\Model\Error;
use HubSpot\Client\Crm\Pipelines\Model\PipelineStage;
use HubSpot\Client\Crm\Properties\Model\Property;
use HubSpot\Discovery\Discovery;
use Jiminny\Component\Utility\Service\ProviderRateLimiter;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Crm\Field;
use Jiminny\Services\Crm\BaseClient;
use Jiminny\Services\Crm\Hubspot\DTO\Response\Owner;
use Jiminny\Services\SocialAccountService;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use SevenShores\Hubspot\Factory;
use SevenShores\Hubspot\Http\Response;
use Jiminny\Services\Crm\Hubspot\Pagination\HubspotPaginationService;
use Throwable;
/**
* @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall
* @return T
*
* @throws RateLimitException
*/
private function executeRequest(callable $apiCall)
{
if (! $this->rateLimiter->canMakeRequest($this->config)) {
$retryAfter = $this->rateLimiter->requestAvailableIn($this->config);
$this->log->warning('[Hubspot] Rate limit exceeded, deferring request', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
]);
throw new RateLimitException(
'Hubspot rate limit reached for configuration ' . $this->config->getId(),
$retryAfter,
);
}
$this->rateLimiter->incrementRequestCount($this->config);
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
private function isHubspotRateLimit(Throwable $e): bool
{
return method_exists($e, 'getCode') && (int) $e->getCode() === 429;
}
private function parseRetryAfter(Throwable $e): int
{
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
return 10;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
$deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
));
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
$response = $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
$response = $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
$max = $response->getHeaderLine('X-HubSpot-RateLimit-Max'); // "110"
$remaining = $response->getHeaderLine('X-HubSpot-RateLimit-Remaining'); // "109"
$interval = $response->getHeaderLine('X-HubSpot-RateLimit-Interval-Milliseconds'); // "10000"
$body = json_decode((string) $response->getBody(), true);
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$max ' . PHP_EOL . print_r($max, true));
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$remaining ' . PHP_EOL . print_r($remaining, true));
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$interval ' . PHP_EOL . print_r($interval, true));
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$body ' . PHP_EOL . print_r($body, true));
return $response;
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"on_screen":true,"help_text":"Git Branch: master","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"[2026-05-07 11:59:07] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":62.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"3cb37764-b6ec-4d4c-85b3-298d24411fec\",\"trace_id\":\"1387c33f-5f58-4299-a3da-9c3ad7e240fe\"}\n[2026-05-07 11:59:07] local.INFO: [ScheduleBotCommand] Number of activities to be captured: 0 {\"correlation_id\":\"3cb37764-b6ec-4d4c-85b3-298d24411fec\",\"trace_id\":\"1387c33f-5f58-4299-a3da-9c3ad7e240fe\"}\n[2026-05-07 11:59:07] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":62.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"3cb37764-b6ec-4d4c-85b3-298d24411fec\",\"trace_id\":\"1387c33f-5f58-4299-a3da-9c3ad7e240fe\"}\n[2026-05-07 11:59:10] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":62.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"997b55b4-ed52-4426-95b2-3d79f48278ae\",\"trace_id\":\"9a0814b7-e0ae-4f6d-ad98-2979c51e16cb\"}\n[2026-05-07 11:59:10] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":62.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"997b55b4-ed52-4426-95b2-3d79f48278ae\",\"trace_id\":\"9a0814b7-e0ae-4f6d-ad98-2979c51e16cb\"}\n[2026-05-07 11:59:13] local.NOTICE: Monitoring start {\"correlation_id\":\"1f069a13-4342-40ed-bf79-1472c9c60637\",\"trace_id\":\"1c2564a5-1d98-4061-819a-060f3143e672\"}\n[2026-05-07 11:59:13] local.NOTICE: Monitoring end {\"correlation_id\":\"1f069a13-4342-40ed-bf79-1472c9c60637\",\"trace_id\":\"1c2564a5-1d98-4061-819a-060f3143e672\"}\n[2026-05-07 11:59:15] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":62.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"92fadd4f-de00-4eae-8e71-26517f0e405c\",\"trace_id\":\"034b1cf6-05b1-455d-9d58-e7286ec06e25\"}\n[2026-05-07 11:59:15] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":62.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"92fadd4f-de00-4eae-8e71-26517f0e405c\",\"trace_id\":\"034b1cf6-05b1-455d-9d58-e7286ec06e25\"}\n[2026-05-07 11:59:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":62.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"2bbdc0e4-afb2-4fa9-bbf7-b67fa2ca32cc\",\"trace_id\":\"a7cdd06b-a602-49f9-a0f7-24736d4d641a\"}\n[2026-05-07 11:59:17] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"2bbdc0e4-afb2-4fa9-bbf7-b67fa2ca32cc\",\"trace_id\":\"a7cdd06b-a602-49f9-a0f7-24736d4d641a\"}\n[2026-05-07 11:59:17] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"2bbdc0e4-afb2-4fa9-bbf7-b67fa2ca32cc\",\"trace_id\":\"a7cdd06b-a602-49f9-a0f7-24736d4d641a\"}\n[2026-05-07 11:59:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":62.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"2bbdc0e4-afb2-4fa9-bbf7-b67fa2ca32cc\",\"trace_id\":\"a7cdd06b-a602-49f9-a0f7-24736d4d641a\"}","depth":4,"on_screen":true,"value":"[2026-05-07 11:59:07] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":62.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"3cb37764-b6ec-4d4c-85b3-298d24411fec\",\"trace_id\":\"1387c33f-5f58-4299-a3da-9c3ad7e240fe\"}\n[2026-05-07 11:59:07] local.INFO: [ScheduleBotCommand] Number of activities to be captured: 0 {\"correlation_id\":\"3cb37764-b6ec-4d4c-85b3-298d24411fec\",\"trace_id\":\"1387c33f-5f58-4299-a3da-9c3ad7e240fe\"}\n[2026-05-07 11:59:07] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":62.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"3cb37764-b6ec-4d4c-85b3-298d24411fec\",\"trace_id\":\"1387c33f-5f58-4299-a3da-9c3ad7e240fe\"}\n[2026-05-07 11:59:10] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":62.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"997b55b4-ed52-4426-95b2-3d79f48278ae\",\"trace_id\":\"9a0814b7-e0ae-4f6d-ad98-2979c51e16cb\"}\n[2026-05-07 11:59:10] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":62.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"997b55b4-ed52-4426-95b2-3d79f48278ae\",\"trace_id\":\"9a0814b7-e0ae-4f6d-ad98-2979c51e16cb\"}\n[2026-05-07 11:59:13] local.NOTICE: Monitoring start {\"correlation_id\":\"1f069a13-4342-40ed-bf79-1472c9c60637\",\"trace_id\":\"1c2564a5-1d98-4061-819a-060f3143e672\"}\n[2026-05-07 11:59:13] local.NOTICE: Monitoring end {\"correlation_id\":\"1f069a13-4342-40ed-bf79-1472c9c60637\",\"trace_id\":\"1c2564a5-1d98-4061-819a-060f3143e672\"}\n[2026-05-07 11:59:15] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":62.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"92fadd4f-de00-4eae-8e71-26517f0e405c\",\"trace_id\":\"034b1cf6-05b1-455d-9d58-e7286ec06e25\"}\n[2026-05-07 11:59:15] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":62.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"92fadd4f-de00-4eae-8e71-26517f0e405c\",\"trace_id\":\"034b1cf6-05b1-455d-9d58-e7286ec06e25\"}\n[2026-05-07 11:59:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":62.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"2bbdc0e4-afb2-4fa9-bbf7-b67fa2ca32cc\",\"trace_id\":\"a7cdd06b-a602-49f9-a0f7-24736d4d641a\"}\n[2026-05-07 11:59:17] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"2bbdc0e4-afb2-4fa9-bbf7-b67fa2ca32cc\",\"trace_id\":\"a7cdd06b-a602-49f9-a0f7-24736d4d641a\"}\n[2026-05-07 11:59:17] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"2bbdc0e4-afb2-4fa9-bbf7-b67fa2ca32cc\",\"trace_id\":\"a7cdd06b-a602-49f9-a0f7-24736d4d641a\"}\n[2026-05-07 11:59:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":62.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"2bbdc0e4-afb2-4fa9-bbf7-b67fa2ca32cc\",\"trace_id\":\"a7cdd06b-a602-49f9-a0f7-24736d4d641a\"}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.016666668,"height":0.02111111},"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"60","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.021527778,"height":0.02111111},"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.015277778,"height":0.025555555},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.014583333,"height":0.025555555},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Component\\Utility\\Service\\ProviderRateLimiter;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n private ProviderRateLimiter $rateLimiter;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager,\n ProviderRateLimiter $rateLimiter,\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n $this->rateLimiter = $rateLimiter;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Single entry point for every HubSpot API call. Enforces the per-portal\n * rate limit configured in the rate_limits table (morphed to the current\n * Configuration) and reacts to a real 429 from HubSpot by translating it\n * into a RateLimitException carrying Retry-After.\n *\n * Wrap any outbound HubSpot call (SDK or raw HTTP) like:\n *\n * $this->executeRequest(fn () => $this->getNewInstance()->crm()->...);\n *\n * @template T\n * @param callable(): T $apiCall\n * @return T\n *\n * @throws RateLimitException\n */\n private function executeRequest(callable $apiCall)\n {\n if (! $this->rateLimiter->canMakeRequest($this->config)) {\n $retryAfter = $this->rateLimiter->requestAvailableIn($this->config);\n\n $this->log->warning('[Hubspot] Rate limit exceeded, deferring request', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n ]);\n\n throw new RateLimitException(\n 'Hubspot rate limit reached for configuration ' . $this->config->getId(),\n $retryAfter,\n );\n }\n\n $this->rateLimiter->incrementRequestCount($this->config);\n\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n private function isHubspotRateLimit(Throwable $e): bool\n {\n return method_exists($e, 'getCode') && (int) $e->getCode() === 429;\n }\n\n private function parseRetryAfter(Throwable $e): int\n {\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n return 10;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n ));\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n $response = $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n $response = $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n\n $max = $response->getHeaderLine('X-HubSpot-RateLimit-Max'); // \"110\"\n $remaining = $response->getHeaderLine('X-HubSpot-RateLimit-Remaining'); // \"109\"\n $interval = $response->getHeaderLine('X-HubSpot-RateLimit-Interval-Milliseconds'); // \"10000\"\n $body = json_decode((string) $response->getBody(), true);\n\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$max ' . PHP_EOL . print_r($max, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$remaining ' . PHP_EOL . print_r($remaining, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$interval ' . PHP_EOL . print_r($interval, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$body ' . PHP_EOL . print_r($body, true));\n\n return $response;\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Component\\Utility\\Service\\ProviderRateLimiter;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n private ProviderRateLimiter $rateLimiter;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager,\n ProviderRateLimiter $rateLimiter,\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n $this->rateLimiter = $rateLimiter;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Single entry point for every HubSpot API call. Enforces the per-portal\n * rate limit configured in the rate_limits table (morphed to the current\n * Configuration) and reacts to a real 429 from HubSpot by translating it\n * into a RateLimitException carrying Retry-After.\n *\n * Wrap any outbound HubSpot call (SDK or raw HTTP) like:\n *\n * $this->executeRequest(fn () => $this->getNewInstance()->crm()->...);\n *\n * @template T\n * @param callable(): T $apiCall\n * @return T\n *\n * @throws RateLimitException\n */\n private function executeRequest(callable $apiCall)\n {\n if (! $this->rateLimiter->canMakeRequest($this->config)) {\n $retryAfter = $this->rateLimiter->requestAvailableIn($this->config);\n\n $this->log->warning('[Hubspot] Rate limit exceeded, deferring request', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n ]);\n\n throw new RateLimitException(\n 'Hubspot rate limit reached for configuration ' . $this->config->getId(),\n $retryAfter,\n );\n }\n\n $this->rateLimiter->incrementRequestCount($this->config);\n\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n private function isHubspotRateLimit(Throwable $e): bool\n {\n return method_exists($e, 'getCode') && (int) $e->getCode() === 429;\n }\n\n private function parseRetryAfter(Throwable $e): int\n {\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n return 10;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n ));\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n $response = $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n $response = $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n\n $max = $response->getHeaderLine('X-HubSpot-RateLimit-Max'); // \"110\"\n $remaining = $response->getHeaderLine('X-HubSpot-RateLimit-Remaining'); // \"109\"\n $interval = $response->getHeaderLine('X-HubSpot-RateLimit-Interval-Milliseconds'); // \"10000\"\n $body = json_decode((string) $response->getBody(), true);\n\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$max ' . PHP_EOL . print_r($max, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$remaining ' . PHP_EOL . print_r($remaining, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$interval ' . PHP_EOL . print_r($interval, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$body ' . PHP_EOL . print_r($body, true));\n\n return $response;\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-5543863607231784606
|
6378759383152203876
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
[2026-05-07 11:59:07] local.INFO: Jiminny\Console\Commands\Command::run Memory usage before starting command {"command":"meeting-bot:schedule-bot","memoryBeforeCommandInMb":62.0,"memoryPeakBeforeCommandInMb":99.727} {"correlation_id":"3cb37764-b6ec-4d4c-85b3-298d24411fec","trace_id":"1387c33f-5f58-4299-a3da-9c3ad7e240fe"}
[2026-05-07 11:59:07] local.INFO: [ScheduleBotCommand] Number of activities to be captured: 0 {"correlation_id":"3cb37764-b6ec-4d4c-85b3-298d24411fec","trace_id":"1387c33f-5f58-4299-a3da-9c3ad7e240fe"}
[2026-05-07 11:59:07] local.INFO: Jiminny\Console\Commands\Command::run Memory usage for command {"command":"meeting-bot:schedule-bot","memoryBeforeCommandInMb":62.0,"memoryAfterCommandInMB":62.0,"memoryPeakBeforeCommandInMb":99.727,"memoryPeakAfterCommandInMB":99.727} {"correlation_id":"3cb37764-b6ec-4d4c-85b3-298d24411fec","trace_id":"1387c33f-5f58-4299-a3da-9c3ad7e240fe"}
[2026-05-07 11:59:10] local.INFO: Jiminny\Console\Commands\Command::run Memory usage before starting command {"command":"dialers:monitor-activities","memoryBeforeCommandInMb":62.0,"memoryPeakBeforeCommandInMb":99.727} {"correlation_id":"997b55b4-ed52-4426-95b2-3d79f48278ae","trace_id":"9a0814b7-e0ae-4f6d-ad98-2979c51e16cb"}
[2026-05-07 11:59:10] local.INFO: Jiminny\Console\Commands\Command::run Memory usage for command {"command":"dialers:monitor-activities","memoryBeforeCommandInMb":62.0,"memoryAfterCommandInMB":62.0,"memoryPeakBeforeCommandInMb":99.727,"memoryPeakAfterCommandInMB":99.727} {"correlation_id":"997b55b4-ed52-4426-95b2-3d79f48278ae","trace_id":"9a0814b7-e0ae-4f6d-ad98-2979c51e16cb"}
[2026-05-07 11:59:13] local.NOTICE: Monitoring start {"correlation_id":"1f069a13-4342-40ed-bf79-1472c9c60637","trace_id":"1c2564a5-1d98-4061-819a-060f3143e672"}
[2026-05-07 11:59:13] local.NOTICE: Monitoring end {"correlation_id":"1f069a13-4342-40ed-bf79-1472c9c60637","trace_id":"1c2564a5-1d98-4061-819a-060f3143e672"}
[2026-05-07 11:59:15] local.INFO: Jiminny\Console\Commands\Command::run Memory usage before starting command {"command":"mailbox:skip-lists:refresh","memoryBeforeCommandInMb":62.0,"memoryPeakBeforeCommandInMb":99.727} {"correlation_id":"92fadd4f-de00-4eae-8e71-26517f0e405c","trace_id":"034b1cf6-05b1-455d-9d58-e7286ec06e25"}
[2026-05-07 11:59:15] local.INFO: Jiminny\Console\Commands\Command::run Memory usage for command {"command":"mailbox:skip-lists:refresh","memoryBeforeCommandInMb":62.0,"memoryAfterCommandInMB":62.0,"memoryPeakBeforeCommandInMb":99.727,"memoryPeakAfterCommandInMB":99.727} {"correlation_id":"92fadd4f-de00-4eae-8e71-26517f0e405c","trace_id":"034b1cf6-05b1-455d-9d58-e7286ec06e25"}
[2026-05-07 11:59:17] local.INFO: Jiminny\Console\Commands\Command::run Memory usage before starting command {"command":"mailbox:batch:process","memoryBeforeCommandInMb":62.0,"memoryPeakBeforeCommandInMb":99.727} {"correlation_id":"2bbdc0e4-afb2-4fa9-bbf7-b67fa2ca32cc","trace_id":"a7cdd06b-a602-49f9-a0f7-24736d4d641a"}
[2026-05-07 11:59:17] local.INFO: [EmailSchedule] STARTING batch process {"host":"docker_lamp_1"} {"correlation_id":"2bbdc0e4-afb2-4fa9-bbf7-b67fa2ca32cc","trace_id":"a7cdd06b-a602-49f9-a0f7-24736d4d641a"}
[2026-05-07 11:59:17] local.INFO: [EmailSchedule] FINISHED batch process {"host":"docker_lamp_1","processed":0} {"correlation_id":"2bbdc0e4-afb2-4fa9-bbf7-b67fa2ca32cc","trace_id":"a7cdd06b-a602-49f9-a0f7-24736d4d641a"}
[2026-05-07 11:59:17] local.INFO: Jiminny\Console\Commands\Command::run Memory usage for command {"command":"mailbox:batch:process","memoryBeforeCommandInMb":62.0,"memoryAfterCommandInMB":62.0,"memoryPeakBeforeCommandInMb":99.727,"memoryPeakAfterCommandInMB":99.727} {"correlation_id":"2bbdc0e4-afb2-4fa9-bbf7-b67fa2ca32cc","trace_id":"a7cdd06b-a602-49f9-a0f7-24736d4d641a"}
Sync Changes
Hide This Notification
Code changed:
Hide
2
60
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot;
use HubSpot\Client\Crm\Deals\ApiException as DealApiException;
use HubSpot\Client\Crm\Contacts\ApiException as ContactApiException;
use HubSpot\Client\Crm\Companies\ApiException as CompanyApiException;
use HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectWithAssociations as ContactsWithAssociations;
use HubSpot\Client\Crm\Companies\Model\SimplePublicObjectWithAssociations as CompaniesWithAssociations;
use HubSpot\Client\Crm\Deals\Model\SimplePublicObjectWithAssociations as DealWithAssociations;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectInput;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectWithAssociations as ObjectWithAssociations;
use HubSpot\Client\Crm\Pipelines\Model\Error;
use HubSpot\Client\Crm\Pipelines\Model\PipelineStage;
use HubSpot\Client\Crm\Properties\Model\Property;
use HubSpot\Discovery\Discovery;
use Jiminny\Component\Utility\Service\ProviderRateLimiter;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Crm\Field;
use Jiminny\Services\Crm\BaseClient;
use Jiminny\Services\Crm\Hubspot\DTO\Response\Owner;
use Jiminny\Services\SocialAccountService;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use SevenShores\Hubspot\Factory;
use SevenShores\Hubspot\Http\Response;
use Jiminny\Services\Crm\Hubspot\Pagination\HubspotPaginationService;
use Throwable;
/**
* @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall
* @return T
*
* @throws RateLimitException
*/
private function executeRequest(callable $apiCall)
{
if (! $this->rateLimiter->canMakeRequest($this->config)) {
$retryAfter = $this->rateLimiter->requestAvailableIn($this->config);
$this->log->warning('[Hubspot] Rate limit exceeded, deferring request', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
]);
throw new RateLimitException(
'Hubspot rate limit reached for configuration ' . $this->config->getId(),
$retryAfter,
);
}
$this->rateLimiter->incrementRequestCount($this->config);
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
private function isHubspotRateLimit(Throwable $e): bool
{
return method_exists($e, 'getCode') && (int) $e->getCode() === 429;
}
private function parseRetryAfter(Throwable $e): int
{
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
return 10;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
$deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
));
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
$response = $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
$response = $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
$max = $response->getHeaderLine('X-HubSpot-RateLimit-Max'); // "110"
$remaining = $response->getHeaderLine('X-HubSpot-RateLimit-Remaining'); // "109"
$interval = $response->getHeaderLine('X-HubSpot-RateLimit-Interval-Milliseconds'); // "10000"
$body = json_decode((string) $response->getBody(), true);
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$max ' . PHP_EOL . print_r($max, true));
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$remaining ' . PHP_EOL . print_r($remaining, true));
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$interval ' . PHP_EOL . print_r($interval, true));
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$body ' . PHP_EOL . print_r($body, true));
return $response;
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
3072
|
NULL
|
NULL
|
NULL
|
|
3250
|
124
|
43
|
2026-05-07T12:08:35.162857+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-07/1778 /Users/lukas/.screenpipe/data/data/2026-05-07/1778155715162_m2.jpg...
|
iTerm2
|
NULL
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
PostmanEditVIewWindowmelpHubSpot rate limit impl PostmanEditVIewWindowmelpHubSpot rate limit implementation strategy vcan I call it trom postman 100 timesEvaluated Postman testing methods and rate limit behavior implications ›Yes. easily. Postman has a built-in Collection Runner for this.How to do it1. Save the request to a collection (right-click → Save).2. Click Run collection (the play icon next to the collection name) or open therunner from the bottom-left.3. Set Iterations: 100. Delay: 0 (or a small value like 50ms).4. Hit RunYou'll get a results view showing each iteration's status code response time and (ifyou click into them the headers.What vou'll actuallv seeCince vol connrmed May=110 Tinterval=t dddd•• At Oms delav. 100 iterations: Postman pushes calls as fast as TCP allows —typically 5-10 calls/second on a normal connection. You'll likelv see all 100succeed because 100 < 110 in 10 seconds, and each call's latency naturally spacesthings out. The X-HubSpot-RateLimit-Remaining header willdron from 109 →108 → 107 ... down to maybe ~10-20 by the end, then recover as the 10-secondwindow siides torward.• To deliberatelv hit a 429: set iterations to 120+ with Oms delav. You'llsee thenret ~l0 reruirn2o0. then 2 bulrct of 42es with nol ievname :TEN SECONDIY ROLITNG• To test the search limit instead: point the request at a search endpoint (e.g..POST /crm/v3/obiects/contacts/search with aminimalbody).setiterationsto 10. delav to 0. You'll trigger 429s wi J plicyName: SECONDLY after the 5thcall within a second. Faster and cheader to reproduce than the burst limitKeep going in Claude CodeSwitch to Claude Code and let Claude work directiv in vour.repo. running and testing as it goesWrite a message…Opus 4. AdaptiveHubspot rate limits reference - MDUse timeZone to interpret resetsAt from the daily erCheat sheet: profiling a new portal in PostmanThree calls, in order:1. GEl /account-into/v3/details → portalinto+GET /account-info/v3/api-usage/daily/privameaningful for private apps)3. Skip search probing — the 5/sec is fixedError response shape"message": "You have reached your secondly 1"errorType": "RATE LIMIT","policyName": "SECONDLY"."correlationia": "...","requestId": "..."nolncvname values.• SECONDLY - search bucket (5/sec)• TEN SECONDLY ROLLING - burst bucket (110/10sprivate)• DAILY — private apps dailv ceilingAlways inspect policyName on 429 to know which buchack offOther operational guidelines• Error responses must stay under 5% of total dailycertificationi• Polling endpoints: minimum interval 5 minutes.•Search querv. may 3.000 chars may 18 flters acrorecullts ver query.• Ratch enânoints. 1in to 100 records ner call regdlahhl"supoont Dally • nowXx Hubspot v• SearchYour team is now on the Free plan with 1 admin. You retain editing access and other members are read-only. View team permissions to see who can edit, or upgrade to restore collaboration.GET next off. • POST search •GET Get Eno • GET Read Cop.No environmentvCRM Objects › crm/v3/objects/{object Type) › {object Id) › Read Copy) SaveCOLLECTIONSAssociations V4E Docs Params • Authorization • Headers 8 Body Scripts SettingsCookies• CMS - UPI. Redirects APl Collectioncompanies• COMPAPEQuery ParamsKey>Contactsv propertiesv CRM Objectsvpropertiesv u crm/vs/obiects/obiect Type)associations> D batchv [ fobiect Id}v associationspaginateAssociation> • associations/{to Object Type)archivedGET Readv idPropertvgs: An error occurred.eg. successful operationpath Variables> GET Read Copy> DEL ArchiveView more actions ectType> paTCH Undateobjectld> GET List> PosT Greate> PoST Filter. Sort, and Search CRM ObiectsResponse3 History> CPM Owners› CRM Pipelines> Deals> Engagements> Hubsnot> Iteration run HSIournal & wehhoookc vA• ©Auth> Pronerties>RESEARCHI• SEAPCHI>Ticketsv liceful› Post tilter oer comoany oniv oben deal stagesGET engagements old associated by dealGET enqagements old associated by companycet aot hictorv of nronertv - doal staadGET aet usersGET CE oauth› GET Meetina outcomes per meetina> GET Road all nronertios new>ENVIRONMENTS> SPFCSELOWS§ Connect Git E Console 2 TernValue<string>DescriotionBulk Edit ..A comma separated list or the properties to be returned in<string>A comma separated list of the properties to be returned in<string>A comma separated list of obiect tvoes to retrieve associal<string»faisefalse<String>A comma separated list of obiect types to retrieve associalWhether to return onlv results that have been archived.The name of a proverty whose values are unique for this olValueDescriptionBulk Edit ..<String>(Required)RequiredSend + Get a successful responsea Send + Visualize response*R Send + Write tests100% L2VAIlVariables in requestobiectidC baseUrl› All variablesInu / May 10.00.32<string><string>httos:/lapi.hubao..GGiobals Vault Tooks •- m=m...
|
NULL
|
-2850224816210153963
|
NULL
|
click
|
ocr
|
NULL
|
PostmanEditVIewWindowmelpHubSpot rate limit impl PostmanEditVIewWindowmelpHubSpot rate limit implementation strategy vcan I call it trom postman 100 timesEvaluated Postman testing methods and rate limit behavior implications ›Yes. easily. Postman has a built-in Collection Runner for this.How to do it1. Save the request to a collection (right-click → Save).2. Click Run collection (the play icon next to the collection name) or open therunner from the bottom-left.3. Set Iterations: 100. Delay: 0 (or a small value like 50ms).4. Hit RunYou'll get a results view showing each iteration's status code response time and (ifyou click into them the headers.What vou'll actuallv seeCince vol connrmed May=110 Tinterval=t dddd•• At Oms delav. 100 iterations: Postman pushes calls as fast as TCP allows —typically 5-10 calls/second on a normal connection. You'll likelv see all 100succeed because 100 < 110 in 10 seconds, and each call's latency naturally spacesthings out. The X-HubSpot-RateLimit-Remaining header willdron from 109 →108 → 107 ... down to maybe ~10-20 by the end, then recover as the 10-secondwindow siides torward.• To deliberatelv hit a 429: set iterations to 120+ with Oms delav. You'llsee thenret ~l0 reruirn2o0. then 2 bulrct of 42es with nol ievname :TEN SECONDIY ROLITNG• To test the search limit instead: point the request at a search endpoint (e.g..POST /crm/v3/obiects/contacts/search with aminimalbody).setiterationsto 10. delav to 0. You'll trigger 429s wi J plicyName: SECONDLY after the 5thcall within a second. Faster and cheader to reproduce than the burst limitKeep going in Claude CodeSwitch to Claude Code and let Claude work directiv in vour.repo. running and testing as it goesWrite a message…Opus 4. AdaptiveHubspot rate limits reference - MDUse timeZone to interpret resetsAt from the daily erCheat sheet: profiling a new portal in PostmanThree calls, in order:1. GEl /account-into/v3/details → portalinto+GET /account-info/v3/api-usage/daily/privameaningful for private apps)3. Skip search probing — the 5/sec is fixedError response shape"message": "You have reached your secondly 1"errorType": "RATE LIMIT","policyName": "SECONDLY"."correlationia": "...","requestId": "..."nolncvname values.• SECONDLY - search bucket (5/sec)• TEN SECONDLY ROLLING - burst bucket (110/10sprivate)• DAILY — private apps dailv ceilingAlways inspect policyName on 429 to know which buchack offOther operational guidelines• Error responses must stay under 5% of total dailycertificationi• Polling endpoints: minimum interval 5 minutes.•Search querv. may 3.000 chars may 18 flters acrorecullts ver query.• Ratch enânoints. 1in to 100 records ner call regdlahhl"supoont Dally • nowXx Hubspot v• SearchYour team is now on the Free plan with 1 admin. You retain editing access and other members are read-only. View team permissions to see who can edit, or upgrade to restore collaboration.GET next off. • POST search •GET Get Eno • GET Read Cop.No environmentvCRM Objects › crm/v3/objects/{object Type) › {object Id) › Read Copy) SaveCOLLECTIONSAssociations V4E Docs Params • Authorization • Headers 8 Body Scripts SettingsCookies• CMS - UPI. Redirects APl Collectioncompanies• COMPAPEQuery ParamsKey>Contactsv propertiesv CRM Objectsvpropertiesv u crm/vs/obiects/obiect Type)associations> D batchv [ fobiect Id}v associationspaginateAssociation> • associations/{to Object Type)archivedGET Readv idPropertvgs: An error occurred.eg. successful operationpath Variables> GET Read Copy> DEL ArchiveView more actions ectType> paTCH Undateobjectld> GET List> PosT Greate> PoST Filter. Sort, and Search CRM ObiectsResponse3 History> CPM Owners› CRM Pipelines> Deals> Engagements> Hubsnot> Iteration run HSIournal & wehhoookc vA• ©Auth> Pronerties>RESEARCHI• SEAPCHI>Ticketsv liceful› Post tilter oer comoany oniv oben deal stagesGET engagements old associated by dealGET enqagements old associated by companycet aot hictorv of nronertv - doal staadGET aet usersGET CE oauth› GET Meetina outcomes per meetina> GET Road all nronertios new>ENVIRONMENTS> SPFCSELOWS§ Connect Git E Console 2 TernValue<string>DescriotionBulk Edit ..A comma separated list or the properties to be returned in<string>A comma separated list of the properties to be returned in<string>A comma separated list of obiect tvoes to retrieve associal<string»faisefalse<String>A comma separated list of obiect types to retrieve associalWhether to return onlv results that have been archived.The name of a proverty whose values are unique for this olValueDescriptionBulk Edit ..<String>(Required)RequiredSend + Get a successful responsea Send + Visualize response*R Send + Write tests100% L2VAIlVariables in requestobiectidC baseUrl› All variablesInu / May 10.00.32<string><string>httos:/lapi.hubao..GGiobals Vault Tooks •- m=m...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
3261
|
123
|
43
|
2026-05-07T12:09:11.017103+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-07/1778 /Users/lukas/.screenpipe/data/data/2026-05-07/1778155751017_m1.jpg...
|
iTerm2
|
NULL
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
PostmanFileEditViewWindowHelp$0lohlSupport Daily • PostmanFileEditViewWindowHelp$0lohlSupport Daily • now100% <478DEV (docker)DOCKER- ₴81DEV (docker)H82APP (-zsh)-zsh• $4screenpipe"•$55.95ms DONE-zshThu 7 May 15:09:10T₴1₴6viewsjiminny-worker-processing-delayed: jiminny-worker-processing-delayed_00: stoppedworker-nudges:worker-nudges_00:stoppedjiminny-worker-processing-2:jiminny-worker-processing-2_00: stoppedJiminny-worker-processing-3:7iminny-worker-processing-3_00: stoppedjiminny-worker-processing-4:jiminny-worker-processing-4_00:stoppedjiminny-worker-processing-5: jiminny-worker-processing-5_00: stoppedworker-crm-update:worker-crm-update_00: stoppedworker-analytics:worker-analytics_00: stoppedworker-download:worker-download_00: stoppedworker:worker_00: stoppedjiminny-worker-processing-1:jiminny-worker-processing-1_00: stoppedworker-calendar:worker-calendar_00:stoppedworker-conferences:worker-conferences_00: stoppedworker-crm-sync:worker-crm-sync_00: stoppedworker-audio:worker-audio_00: stoppedworker-emails:worker-emails_00: stoppedartisan-schedule:artisan-schedule_00: stoppedworker-es-update:worker-es-update_00: stoppedartisan-schedule:artisan-schedule_00: startedjiminny-worker-processing-1:jiminny-worker-processing-1_00: startedjiminny-worker-processing-2:1iminny-worker-processing-2 00: startedjiminny-worker-processing-3:jiminny-worker-processing-3_00: startedjiminny-worker-processing-4:jiminny-worker-processing-4_00: startedjiminny-worker-processing-5:jiminny-worker-processing-5_00: startedjiminny-worker-processing-delayed: jiminny-worker-processing-delayed_00: startedworker:worker_00: startedworker-analytics:worker-analytics_00: startedworker-audio:worker-audio_00: startedworker-calendar:worker-calendar_00: startedworker-conferences:worker-conferences_00: startedworker-crm-sync:worker-crm-sync_00: startedworker-crm-update:worker-crm-update_00: startedworker-download:worker-download_00: startedworker-emails:worker-emails_00: startedworker-es-update:worker-es-update_00: startedworker-nudges:worker-nudges_00: startedroot@docker_lamp_1:/home/jiminny# php artisan jiminny:debugSyncing opportunity 0Syncing opportunity 25Syncing opportunity 50Syncing opportunity 75Syncing opportunity 100root@docker_lamp_1:/home/jiminny# ]DEV...
|
NULL
|
-2371774080706617927
|
NULL
|
click
|
ocr
|
NULL
|
PostmanFileEditViewWindowHelp$0lohlSupport Daily • PostmanFileEditViewWindowHelp$0lohlSupport Daily • now100% <478DEV (docker)DOCKER- ₴81DEV (docker)H82APP (-zsh)-zsh• $4screenpipe"•$55.95ms DONE-zshThu 7 May 15:09:10T₴1₴6viewsjiminny-worker-processing-delayed: jiminny-worker-processing-delayed_00: stoppedworker-nudges:worker-nudges_00:stoppedjiminny-worker-processing-2:jiminny-worker-processing-2_00: stoppedJiminny-worker-processing-3:7iminny-worker-processing-3_00: stoppedjiminny-worker-processing-4:jiminny-worker-processing-4_00:stoppedjiminny-worker-processing-5: jiminny-worker-processing-5_00: stoppedworker-crm-update:worker-crm-update_00: stoppedworker-analytics:worker-analytics_00: stoppedworker-download:worker-download_00: stoppedworker:worker_00: stoppedjiminny-worker-processing-1:jiminny-worker-processing-1_00: stoppedworker-calendar:worker-calendar_00:stoppedworker-conferences:worker-conferences_00: stoppedworker-crm-sync:worker-crm-sync_00: stoppedworker-audio:worker-audio_00: stoppedworker-emails:worker-emails_00: stoppedartisan-schedule:artisan-schedule_00: stoppedworker-es-update:worker-es-update_00: stoppedartisan-schedule:artisan-schedule_00: startedjiminny-worker-processing-1:jiminny-worker-processing-1_00: startedjiminny-worker-processing-2:1iminny-worker-processing-2 00: startedjiminny-worker-processing-3:jiminny-worker-processing-3_00: startedjiminny-worker-processing-4:jiminny-worker-processing-4_00: startedjiminny-worker-processing-5:jiminny-worker-processing-5_00: startedjiminny-worker-processing-delayed: jiminny-worker-processing-delayed_00: startedworker:worker_00: startedworker-analytics:worker-analytics_00: startedworker-audio:worker-audio_00: startedworker-calendar:worker-calendar_00: startedworker-conferences:worker-conferences_00: startedworker-crm-sync:worker-crm-sync_00: startedworker-crm-update:worker-crm-update_00: startedworker-download:worker-download_00: startedworker-emails:worker-emails_00: startedworker-es-update:worker-es-update_00: startedworker-nudges:worker-nudges_00: startedroot@docker_lamp_1:/home/jiminny# php artisan jiminny:debugSyncing opportunity 0Syncing opportunity 25Syncing opportunity 50Syncing opportunity 75Syncing opportunity 100root@docker_lamp_1:/home/jiminny# ]DEV...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
3369
|
126
|
43
|
2026-05-07T12:14:48.621285+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-07/1778 /Users/lukas/.screenpipe/data/data/2026-05-07/1778156088621_m2.jpg...
|
iTerm2
|
NULL
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
PostmanEditVIewWindowmelpHubSpot rate limit impl PostmanEditVIewWindowmelpHubSpot rate limit implementation strategy vcan I call it trom postman 100 timesEvaluated Postman testing methods and rate limit behavior implications ›Yes. easily. Postman has a built-in Collection Runner for this.How to do it1. Save the request to a collection (right-click → Save)2. Click Run collection (the play icon next to the collection name) or open therunner from the bottom-left.3. Set Iterations: 100. Delay: 0 (or a small value like 50ms).4. Hit RunYou'll get a results view showing each iteration's status code response time and (ifyou click into them the headers.What vou'll actuallv seeCince vol connrmed May=110 Tinterval=t dddd•• At Oms delav. 100 iterations: Postman pushes calls as fast as TCP allows —typically 5-10 calls/second on a normal connection. You'll likelv see all 100succeed because 100 < 110 in 10 seconds, and each call's latency naturally spacesthings out. The X-HubSpot-RateLimit-Remaining header willdron from 109 →108 → 107 ... down to maybe ~10-20 by the end, then recover as the 10-secondwindow siides torward.• To deliberatelv hit a 429: set iterations to 120+ with Oms delav. You'llsee thenret ~l0 reruirn2o0. then 2 bulrct of 42es with nol ievname :TEN SECONDIY ROLITNG• To test the search limit instead: point the request at a search endpoint (e.g..POST /crm/v3/obiects/contacts/search with aminimalbody).setiterationsto 10. delav to 0. You'll trigger 429s wi J plicyName: SECONDLY after the 5thcall within a second. Faster and cheader to reproduce than the burst limitKeep going in Claude CodeSwitch to Claude Code and let Claude work directiv in vour.repo. running and testing as it goesWrite a message…Opus 4. AdaptiveHubspot rate limits reference - MDUse timeZone to interpret resetsAt from the daily erCheat sheet: profiling a new portal in PostmanThree calls, in order:1. GEl /account-into/v3/details → portalinto+GET /account-info/v3/api-usage/daily/privmeaningful for private apps)3. Skip search probing — the 5/sec is fixedError response shape"message": "You have reached your secondly 1"errorType": "RATE LIMIT","policyName": "SECONDLY"."requestId": "..."nolncvname values.• SECONDLY - search bucket (5/sec)• TEN SECONDLY ROLLING - burst bucket (110/10sprivate)• DAILY — private apps daily ceilingAlways inspect policyName on 429 to know which buchack offOther operational guidelines• Error responses must stay under 5% of total dailycertificationi• Polling endpoints: minimum interval 5 minutes.•Search query. may 3.000 chars. may 18 Alters acrorecullts ver query.• Ratch enânoints. 1in to 100 records ner call regdlahelsuppont Dally • 1m lertQ SearchYour team is now on the Free plan with 1 admin. You retain editing access and other members are read-only. View team permissions to see who can edit, or upgrade to restore collaborationv COLLECtIONsGET aet meetinaPOST get link to taskPosT Create contact with Associationaallla teleltv Iteration run HiSv GET Read Copyeg. An error occurred.ae, successful operationJournal & webhoooks v4OAuth> RESEARCHISEARCHPOST search contact by phonePOST search contact by emaiPost search meeuings> POST Search calls v3POST Search related meetinas v3Post sparch dealsv Usefull› PosT filter per company onlv open deal stagesGET engagements old associated by dealGET engagements old associated by company› GET get history of property - deal stageGET get usersGET SE oauth• GET Meetina outcomes per meetina> Get Read all nronerties new› GET Read all oroverties oldGet old call dicnositioncGET list with associationsdet lict enaaaements.oldGET recent endagementsGET get dealGET Get Engagement (vil)patch httns-/lani bubani comlenaadomentc/v1CAMIDONMCNTC> SPFCS>FLOWS@ Connect Git = ConcoldGET readGET Get!mlteratioD IteratioNo environmentvSEARCH › search deals) Save= DocsAuthorization • Headers 11 Body • ScriptsSettinasCookieseraw• binary • GraphQL JSON ~o Schema Beautifyrilters":"value": 1773041124362"hs_call_direction",200 OK • 319 ms • 1.7 KB fe.g- save kesponse .:statusdateThu, 07 May 2026 11:25:00 GMTIcontent-typeapplication/ison.charsoteutf.ocontent-lenathlct-rav9f7fdc8a7b508428-SOFnf-cache-statusDYNAMIGcontent-encodingstrict-transport-securitymax-age=31536000: includeSubDomains: preloadorigin, accept-encodingaccess-control-allow-credentialsfalseserver-timinahcid:desc="019e022f-12de-744e-9338-bab37cbb56a1", cfr:desc="9f7fdc8a857e3402-IAD"x-content-type-optionsnocniffx-hubspot-correlation-id019e022f-12de-744e-9338-bab37cbb56a1Wondoointe!.ffiuel.httne.lMa.nolcloudflor..com/eonortllo10e._40/0FOw7umV7W2EV7.TOpreport-tof"suecocs fraction".0.01 "renort to"."cf-ne|""may aae".604800}100% L2Thu 7 May 15:14:48UparadeVAIlVariables in requestG tokenCKPur5PaMx ZoiNg,› All Varlables...
|
NULL
|
7226339931754437212
|
NULL
|
visual_change
|
ocr
|
NULL
|
PostmanEditVIewWindowmelpHubSpot rate limit impl PostmanEditVIewWindowmelpHubSpot rate limit implementation strategy vcan I call it trom postman 100 timesEvaluated Postman testing methods and rate limit behavior implications ›Yes. easily. Postman has a built-in Collection Runner for this.How to do it1. Save the request to a collection (right-click → Save)2. Click Run collection (the play icon next to the collection name) or open therunner from the bottom-left.3. Set Iterations: 100. Delay: 0 (or a small value like 50ms).4. Hit RunYou'll get a results view showing each iteration's status code response time and (ifyou click into them the headers.What vou'll actuallv seeCince vol connrmed May=110 Tinterval=t dddd•• At Oms delav. 100 iterations: Postman pushes calls as fast as TCP allows —typically 5-10 calls/second on a normal connection. You'll likelv see all 100succeed because 100 < 110 in 10 seconds, and each call's latency naturally spacesthings out. The X-HubSpot-RateLimit-Remaining header willdron from 109 →108 → 107 ... down to maybe ~10-20 by the end, then recover as the 10-secondwindow siides torward.• To deliberatelv hit a 429: set iterations to 120+ with Oms delav. You'llsee thenret ~l0 reruirn2o0. then 2 bulrct of 42es with nol ievname :TEN SECONDIY ROLITNG• To test the search limit instead: point the request at a search endpoint (e.g..POST /crm/v3/obiects/contacts/search with aminimalbody).setiterationsto 10. delav to 0. You'll trigger 429s wi J plicyName: SECONDLY after the 5thcall within a second. Faster and cheader to reproduce than the burst limitKeep going in Claude CodeSwitch to Claude Code and let Claude work directiv in vour.repo. running and testing as it goesWrite a message…Opus 4. AdaptiveHubspot rate limits reference - MDUse timeZone to interpret resetsAt from the daily erCheat sheet: profiling a new portal in PostmanThree calls, in order:1. GEl /account-into/v3/details → portalinto+GET /account-info/v3/api-usage/daily/privmeaningful for private apps)3. Skip search probing — the 5/sec is fixedError response shape"message": "You have reached your secondly 1"errorType": "RATE LIMIT","policyName": "SECONDLY"."requestId": "..."nolncvname values.• SECONDLY - search bucket (5/sec)• TEN SECONDLY ROLLING - burst bucket (110/10sprivate)• DAILY — private apps daily ceilingAlways inspect policyName on 429 to know which buchack offOther operational guidelines• Error responses must stay under 5% of total dailycertificationi• Polling endpoints: minimum interval 5 minutes.•Search query. may 3.000 chars. may 18 Alters acrorecullts ver query.• Ratch enânoints. 1in to 100 records ner call regdlahelsuppont Dally • 1m lertQ SearchYour team is now on the Free plan with 1 admin. You retain editing access and other members are read-only. View team permissions to see who can edit, or upgrade to restore collaborationv COLLECtIONsGET aet meetinaPOST get link to taskPosT Create contact with Associationaallla teleltv Iteration run HiSv GET Read Copyeg. An error occurred.ae, successful operationJournal & webhoooks v4OAuth> RESEARCHISEARCHPOST search contact by phonePOST search contact by emaiPost search meeuings> POST Search calls v3POST Search related meetinas v3Post sparch dealsv Usefull› PosT filter per company onlv open deal stagesGET engagements old associated by dealGET engagements old associated by company› GET get history of property - deal stageGET get usersGET SE oauth• GET Meetina outcomes per meetina> Get Read all nronerties new› GET Read all oroverties oldGet old call dicnositioncGET list with associationsdet lict enaaaements.oldGET recent endagementsGET get dealGET Get Engagement (vil)patch httns-/lani bubani comlenaadomentc/v1CAMIDONMCNTC> SPFCS>FLOWS@ Connect Git = ConcoldGET readGET Get!mlteratioD IteratioNo environmentvSEARCH › search deals) Save= DocsAuthorization • Headers 11 Body • ScriptsSettinasCookieseraw• binary • GraphQL JSON ~o Schema Beautifyrilters":"value": 1773041124362"hs_call_direction",200 OK • 319 ms • 1.7 KB fe.g- save kesponse .:statusdateThu, 07 May 2026 11:25:00 GMTIcontent-typeapplication/ison.charsoteutf.ocontent-lenathlct-rav9f7fdc8a7b508428-SOFnf-cache-statusDYNAMIGcontent-encodingstrict-transport-securitymax-age=31536000: includeSubDomains: preloadorigin, accept-encodingaccess-control-allow-credentialsfalseserver-timinahcid:desc="019e022f-12de-744e-9338-bab37cbb56a1", cfr:desc="9f7fdc8a857e3402-IAD"x-content-type-optionsnocniffx-hubspot-correlation-id019e022f-12de-744e-9338-bab37cbb56a1Wondoointe!.ffiuel.httne.lMa.nolcloudflor..com/eonortllo10e._40/0FOw7umV7W2EV7.TOpreport-tof"suecocs fraction".0.01 "renort to"."cf-ne|""may aae".604800}100% L2Thu 7 May 15:14:48UparadeVAIlVariables in requestG tokenCKPur5PaMx ZoiNg,› All Varlables...
|
3368
|
NULL
|
NULL
|
NULL
|
|
3767
|
136
|
43
|
2026-05-07T12:39:53.783243+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-07/1778 /Users/lukas/.screenpipe/data/data/2026-05-07/1778157593783_m2.jpg...
|
Firefox
|
Search the CRM - HubSpot docs — Work
|
True
|
developers.hubspot.com/docs/api-reference/latest/c developers.hubspot.com/docs/api-reference/latest/crm/search-the-crm#limits...
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 3 Q2 - Platform Team - Scrum Board Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
SevenShores\Hubspot\Exceptions\BadRequest: Client error: `POST [URL_WITH_CREDENTIALS]
}
]
}
]
}
Each object that you search will include a set of
default properties
default properties
that gets returned. For contacts, a search will return
createdate
,
email
,
firstname
,
hs_object_id
,
lastmodifieddate
, and
lastname
. For example, the above request would return the following response:
Report incorrect code
Copy the contents from the code block
Ask AI
{
"total"
:
2
,
"results"
: [
{
"id"
:
"100451"
,
"properties"
: {
"createdate"
:
"2024-01-17T19:55:04.281Z"
,
"email"
:
"[EMAIL]"
,
"firstname"
:
"Test"
,
"hs_object_id"
:
"100451"
,
"lastmodifieddate"
:
"2024-09-11T13:27:39.356Z"
,
"lastname"
:
"Person"
},
"createdAt"
:
"2024-01-17T19:55:04.281Z"
,
"updatedAt"
:
"2024-09-11T13:27:39.356Z"
,
"archived"
:
false
},
{
"id"
:
"57156923994"
,
"properties"
: {
"createdate"
:
"2024-09-11T18:21:50.012Z"
,
"email"
:
"[EMAIL]"
,
"firstname"
:
"Maria"
,
"hs_object_id"
:
"57156923994"
,
"lastmodifieddate"
:
"2024-10-21T21:36:02.961Z"
,
"lastname"
:
"Johnson (Sample Contact)"
},
"createdAt"
:
"2024-09-11T18:21:50.012Z"
,
"updatedAt"
:
"2024-10-21T21:36:02.961Z"
,
"archived"
:
false
}
]
}
To return a specific set of properties, include a
properties
array in the request body. For example:
Report incorrect code
Copy the contents from the code block
Ask AI
{
"filterGroups"
: [
{
"filters"
: [
{
"propertyName"
:
"annualrevenue"
,
"operator"
:
"GT"
,
"value"
:
"10000000"
}
]
}
],
"properties"
: [
"annualrevenue"
,
"name"
]
}
The response for the above request would look like:
Report incorrect code
Copy the contents from the code block
Ask AI
{
"total"
:
38
,
"results"
: [
{
"id"
:
"2810868468"
,
"properties"
: {
"annualrevenue"
:
"1000000000"
,
"createdate"
:
"2020-01-09T20:11:27.309Z"
,
"hs_lastmodifieddate"
:
"2024-09-13T20:23:03.333Z"
,
"hs_object_id"
:
"2810868468"
,
"name"
:
"Google"
},
"createdAt"
:
"2020-01-09T20:11:27.309Z"
,
"updatedAt"
:
"2024-09-13T20:23:03.333Z"
,
"archived"
:
false
},
{
"id"
:
"2823023532"
,
"properties"
: {
"annualrevenue"
:
"10000000000"
,
"createdate"
:
"2020-01-13T16:21:08.270Z"
,
"hs_lastmodifieddate"
:
"2024-09-13T20:23:03.064Z"
,
"hs_object_id"
:
"2823023532"
,
"name"
:
"Pepsi"
},
"createdAt"...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.34773937,"top":0.0518755,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira","depth":5,"bounds":{"left":0.36103722,"top":0.06304868,"width":0.10106383,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SevenShores\\Hubspot\\Exceptions\\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your secondly limit.\",\"errorType\":\"RATE_LIMIT","depth":4,"bounds":{"left":0.34773937,"top":0.08459697,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SevenShores\\Hubspot\\Exceptions\\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your secondly limit.\",\"errorType\":\"RATE_LIMIT","depth":5,"bounds":{"left":0.36103722,"top":0.09577015,"width":0.4644282,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Service-Desk - Queues - Platform team - Service space - Jira","depth":4,"bounds":{"left":0.34773937,"top":0.11731844,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Service-Desk - Queues - Platform team - Service space - Jira","depth":5,"bounds":{"left":0.36103722,"top":0.12849163,"width":0.10721409,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app","depth":4,"bounds":{"left":0.34773937,"top":0.15003991,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app","depth":5,"bounds":{"left":0.36103722,"top":0.16121309,"width":0.17037898,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Sentry","depth":4,"bounds":{"left":0.34773937,"top":0.18276137,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sentry","depth":5,"bounds":{"left":0.36103722,"top":0.19393456,"width":0.011303191,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Pull requests · jiminny/app","depth":4,"bounds":{"left":0.34773937,"top":0.21548285,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests · jiminny/app","depth":5,"bounds":{"left":0.36103722,"top":0.22665602,"width":0.04537899,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Userpilot | Ask Jiminny Report Generated","depth":4,"bounds":{"left":0.34773937,"top":0.2482043,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Userpilot | Ask Jiminny Report Generated","depth":5,"bounds":{"left":0.36103722,"top":0.25937748,"width":0.07164229,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app","depth":4,"bounds":{"left":0.34773937,"top":0.28092578,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app","depth":5,"bounds":{"left":0.36103722,"top":0.29209897,"width":0.19331782,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"bounds":{"left":0.34773937,"top":0.31364724,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"bounds":{"left":0.36103722,"top":0.32482043,"width":0.013131649,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Search the CRM - HubSpot docs","depth":4,"bounds":{"left":0.34773937,"top":0.3463687,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Search the CRM - HubSpot docs","depth":5,"bounds":{"left":0.36103722,"top":0.3575419,"width":0.05651596,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.41505983,"top":0.35355148,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.35056517,"top":0.38068634,"width":0.07413564,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.35056517,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"bounds":{"left":0.3615359,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"bounds":{"left":0.3726729,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.38380983,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.3949468,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Skip to main content","depth":6,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip to main content","depth":7,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"HubSpot docs home page light logo","depth":7,"bounds":{"left":0.44331783,"top":0.06624102,"width":0.08045213,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"HubSpot docs","depth":9,"bounds":{"left":0.4429854,"top":0.06703911,"width":0.03557181,"height":0.015961692},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"home page","depth":9,"bounds":{"left":0.47855717,"top":0.06703911,"width":0.029920213,"height":0.015961692},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"2026-03","depth":7,"bounds":{"left":0.5290891,"top":0.06464485,"width":0.029753989,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2026-03","depth":9,"bounds":{"left":0.53241354,"top":0.07063048,"width":0.017785905,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Open search","depth":7,"bounds":{"left":0.6253325,"top":0.06304868,"width":0.13081782,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Search...","depth":9,"bounds":{"left":0.63796544,"top":0.07063048,"width":0.018284574,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"⌘","depth":9,"bounds":{"left":0.74551195,"top":0.071428575,"width":0.003656915,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"K","depth":9,"bounds":{"left":0.7491689,"top":0.071428575,"width":0.0029920214,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle assistant panel","depth":7,"bounds":{"left":0.75947475,"top":0.06304868,"width":0.04255319,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Ask AI","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Ask Docs AI","depth":9,"bounds":{"left":0.77077794,"top":0.07063048,"width":0.026595745,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Changelog","depth":10,"bounds":{"left":0.9049202,"top":0.06943336,"width":0.023603724,"height":0.015961692},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Changelog","depth":11,"bounds":{"left":0.9049202,"top":0.07063048,"width":0.023603724,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Log In","depth":10,"bounds":{"left":0.93650264,"top":0.06943336,"width":0.014295213,"height":0.015961692},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Log In","depth":11,"bounds":{"left":0.93650264,"top":0.07063048,"width":0.014295213,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Sign up","depth":10,"bounds":{"left":0.9587766,"top":0.06304868,"width":0.025265958,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sign up","depth":12,"bounds":{"left":0.9587766,"top":0.07063048,"width":0.01662234,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Home","depth":7,"bounds":{"left":0.44331783,"top":0.10295291,"width":0.013131649,"height":0.03830806},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Home","depth":8,"bounds":{"left":0.44331783,"top":0.11532322,"width":0.013131649,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Get Started","depth":7,"bounds":{"left":0.4644282,"top":0.10295291,"width":0.025764627,"height":0.03830806},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Get Started","depth":8,"bounds":{"left":0.4644282,"top":0.11532322,"width":0.025764627,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Apps","depth":7,"bounds":{"left":0.49817154,"top":0.10295291,"width":0.011136968,"height":0.03830806},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Apps","depth":8,"bounds":{"left":0.49817154,"top":0.11532322,"width":0.011136968,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"CMS","depth":7,"bounds":{"left":0.51728725,"top":0.10295291,"width":0.009973404,"height":0.03830806},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"CMS","depth":8,"bounds":{"left":0.51728725,"top":0.11532322,"width":0.009973404,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"APIs","depth":7,"bounds":{"left":0.53523934,"top":0.10295291,"width":0.010305851,"height":0.03830806},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"APIs","depth":8,"bounds":{"left":0.53523934,"top":0.11532322,"width":0.010305851,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Developer Tooling","depth":7,"bounds":{"left":0.55352396,"top":0.10295291,"width":0.0390625,"height":0.03830806},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Developer Tooling","depth":8,"bounds":{"left":0.55352396,"top":0.11532322,"width":0.0390625,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Overview","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Overview","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Web and mobile SDKs","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Web and mobile SDKs","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Sunsetted and deprecated APIs","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sunsetted and deprecated APIs","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Error handling","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Error handling","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Account & Settings","depth":8,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Account & Settings","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Account information section","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Account information","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Audit Logs section","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Audit Logs","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Brands section","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Brands","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle IP ranges section","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"IP ranges","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Settings section","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Settings","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"App Management","depth":8,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"App Management","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle App Uninstalls section","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"App Uninstalls","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Feature Flags section","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Feature Flags","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Authentication","depth":8,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Authentication","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"API Guide","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"API Guide","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle OAuth tokens section","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OAuth tokens","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Automation","depth":8,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Automation","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Sequences section","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Sequences","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Workflow actions section","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Workflow actions","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"CMS","depth":8,"bounds":{"left":0.44331783,"top":0.0,"width":0.010139627,"height":0.015961692},"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"CMS","depth":9,"bounds":{"left":0.44331783,"top":0.0,"width":0.010139627,"height":0.01396648},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Blogs section","depth":10,"bounds":{"left":0.43001994,"top":0.0,"width":0.027260639,"height":0.025538707},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Blogs","depth":11,"bounds":{"left":0.44132313,"top":0.0,"width":0.011968086,"height":0.01396648},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Content audit section","depth":10,"bounds":{"left":0.43001994,"top":0.0,"width":0.04537899,"height":0.025538707},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Content audit","depth":11,"bounds":{"left":0.44132313,"top":0.0,"width":0.030086435,"height":0.01396648},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Domains section","depth":10,"bounds":{"left":0.43001994,"top":0.0,"width":0.03474069,"height":0.025538707},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Domains","depth":11,"bounds":{"left":0.44132313,"top":0.0,"width":0.019448139,"height":0.01396648},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle HubDB section","depth":10,"bounds":{"left":0.43001994,"top":0.01715882,"width":0.030917553,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"HubDB","depth":11,"bounds":{"left":0.44132313,"top":0.023144454,"width":0.015625,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Media Bridge section","depth":10,"bounds":{"left":0.43001994,"top":0.04349561,"width":0.044714097,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Media Bridge","depth":11,"bounds":{"left":0.44132313,"top":0.049481247,"width":0.029421542,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Pages section","depth":10,"bounds":{"left":0.43001994,"top":0.0698324,"width":0.028756648,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Pages","depth":11,"bounds":{"left":0.44132313,"top":0.07581804,"width":0.013464096,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Site Search section","depth":10,"bounds":{"left":0.43001994,"top":0.096169196,"width":0.040059842,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Site Search","depth":11,"bounds":{"left":0.44132313,"top":0.10215483,"width":0.024767287,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Source code section","depth":10,"bounds":{"left":0.43001994,"top":0.122505985,"width":0.042386968,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Source code","depth":11,"bounds":{"left":0.44132313,"top":0.12849163,"width":0.027094414,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle URL mappings section","depth":10,"bounds":{"left":0.43001994,"top":0.14884278,"width":0.047706116,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"URL mappings","depth":11,"bounds":{"left":0.44132313,"top":0.15482841,"width":0.032413565,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle URL redirects section","depth":10,"bounds":{"left":0.43001994,"top":0.17517957,"width":0.04488032,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"URL redirects","depth":11,"bounds":{"left":0.44132313,"top":0.1811652,"width":0.029587766,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Communication preferences","depth":8,"bounds":{"left":0.44331783,"top":0.22625698,"width":0.06349734,"height":0.015961692},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Communication preferences","depth":9,"bounds":{"left":0.44331783,"top":0.22745411,"width":0.06349734,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"API Guide","depth":10,"bounds":{"left":0.43583778,"top":0.25019953,"width":0.07729388,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"API Guide","depth":12,"bounds":{"left":0.44115692,"top":0.25618514,"width":0.02244016,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Status section","depth":10,"bounds":{"left":0.43001994,"top":0.27653632,"width":0.029421542,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Status","depth":11,"bounds":{"left":0.44132313,"top":0.28252193,"width":0.01412899,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Conversations","depth":8,"bounds":{"left":0.44331783,"top":0.32761374,"width":0.032081116,"height":0.015961692},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversations","depth":9,"bounds":{"left":0.44331783,"top":0.32881084,"width":0.032081116,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Overview","depth":10,"bounds":{"left":0.43583778,"top":0.35155627,"width":0.07729388,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Overview","depth":12,"bounds":{"left":0.44115692,"top":0.3575419,"width":0.020611702,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Chat Configuration section","depth":10,"bounds":{"left":0.43001994,"top":0.37789306,"width":0.05718085,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Chat Configuration","depth":11,"bounds":{"left":0.44132313,"top":0.38387868,"width":0.041888297,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Custom Channels section","depth":10,"bounds":{"left":0.43001994,"top":0.40422985,"width":0.053357713,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Custom Channels","depth":11,"bounds":{"left":0.44132313,"top":0.4102155,"width":0.038065158,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Visitor identification section","depth":10,"bounds":{"left":0.43001994,"top":0.43056664,"width":0.059674203,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Visitor identification","depth":11,"bounds":{"left":0.44132313,"top":0.4365523,"width":0.04438165,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"CRM","depth":8,"bounds":{"left":0.44331783,"top":0.48164406,"width":0.010472074,"height":0.015961692},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"CRM","depth":9,"bounds":{"left":0.44331783,"top":0.4828412,"width":0.010472074,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"CRM embed","depth":10,"bounds":{"left":0.43583778,"top":0.50558656,"width":0.07729388,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"CRM embed","depth":12,"bounds":{"left":0.44115692,"top":0.51157224,"width":0.026761968,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Search the CRM","depth":10,"bounds":{"left":0.43583778,"top":0.5319234,"width":0.07729388,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Search the CRM","depth":12,"bounds":{"left":0.44115692,"top":0.53790903,"width":0.034906916,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Understanding the CRM","depth":10,"bounds":{"left":0.43583778,"top":0.5582602,"width":0.07729388,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Understanding the CRM","depth":12,"bounds":{"left":0.44115692,"top":0.5642458,"width":0.052526597,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Using object APIs","depth":10,"bounds":{"left":0.43583778,"top":0.584597,"width":0.07729388,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Using object APIs","depth":12,"bounds":{"left":0.44115692,"top":0.5905826,"width":0.0390625,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Activities section","depth":10,"bounds":{"left":0.43001994,"top":0.6109338,"width":0.03523936,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Activities","depth":11,"bounds":{"left":0.44132313,"top":0.6169194,"width":0.019946808,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Associations section","depth":10,"bounds":{"left":0.43001994,"top":0.63727057,"width":0.04288564,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Associations","depth":11,"bounds":{"left":0.44132313,"top":0.6432562,"width":0.027593086,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Exports section","depth":10,"bounds":{"left":0.43001994,"top":0.66360736,"width":0.032247342,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Exports","depth":11,"bounds":{"left":0.44132313,"top":0.669593,"width":0.016954787,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Extensions section","depth":10,"bounds":{"left":0.43001994,"top":0.68994415,"width":0.03873005,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Extensions","depth":11,"bounds":{"left":0.44132313,"top":0.69592977,"width":0.0234375,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Imports section","depth":10,"bounds":{"left":0.43001994,"top":0.71628094,"width":0.03324468,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Imports","depth":11,"bounds":{"left":0.44132313,"top":0.72226655,"width":0.017952127,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Limits Tracking section","depth":10,"bounds":{"left":0.43001994,"top":0.7426177,"width":0.048537236,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Limits Tracking","depth":11,"bounds":{"left":0.44132313,"top":0.74860334,"width":0.03324468,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Lists section","depth":10,"bounds":{"left":0.43001994,"top":0.7689545,"width":0.02543218,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Lists","depth":11,"bounds":{"left":0.44132313,"top":0.77494013,"width":0.010139627,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Objects section","depth":10,"bounds":{"left":0.43001994,"top":0.7952913,"width":0.032081116,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Objects","depth":11,"bounds":{"left":0.44132313,"top":0.8012769,"width":0.016788565,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Owners section","depth":10,"bounds":{"left":0.43001994,"top":0.8216281,"width":0.03174867,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Owners","depth":11,"bounds":{"left":0.44132313,"top":0.8276137,"width":0.016456118,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Pipelines section","depth":10,"bounds":{"left":0.43001994,"top":0.8479649,"width":0.03474069,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Pipelines","depth":11,"bounds":{"left":0.44132313,"top":0.8539505,"width":0.019448139,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Properties section","depth":10,"bounds":{"left":0.43001994,"top":0.8743017,"width":0.037732713,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Properties","depth":11,"bounds":{"left":0.44132313,"top":0.8802873,"width":0.02244016,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Property Validations section","depth":10,"bounds":{"left":0.43001994,"top":0.90063846,"width":0.06000665,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Property Validations","depth":11,"bounds":{"left":0.44132313,"top":0.9066241,"width":0.044714097,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Events","depth":8,"bounds":{"left":0.44331783,"top":0.9517159,"width":0.014960106,"height":0.015961692},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Events","depth":9,"bounds":{"left":0.44331783,"top":0.952913,"width":0.014960106,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"API Guide","depth":10,"bounds":{"left":0.43583778,"top":0.9756584,"width":0.07729388,"height":0.024341583},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"API Guide","depth":12,"bounds":{"left":0.44115692,"top":0.98164403,"width":0.02244016,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Define events section","depth":10,"bounds":{"left":0.43001994,"top":1.0,"width":0.045212764,"height":-0.0019952059},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Define events","depth":11,"bounds":{"left":0.44132313,"top":1.0,"width":0.029920213,"height":-0.0079808235},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Retrieve events section","depth":10,"bounds":{"left":0.43001994,"top":1.0,"width":0.04886968,"height":-0.028331995},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Retrieve events","depth":11,"bounds":{"left":0.44132313,"top":1.0,"width":0.03357713,"height":-0.034317613},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Send event data section","depth":10,"bounds":{"left":0.43001994,"top":1.0,"width":0.051363032,"height":-0.054668784},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Send event data","depth":11,"bounds":{"left":0.44132313,"top":1.0,"width":0.036070477,"height":-0.0606544},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Files","depth":8,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Files","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"API Guide","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"API Guide","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Files section","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Files","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Folders section","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Folders","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Marketing","depth":8,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Marketing","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Campaigns section","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Campaigns","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle CTAs section","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"CTAs","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Forms section","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Forms","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Marketing Emails section","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Marketing Emails","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Marketing Events section","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Marketing Events","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Transactional Emails section","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Transactional Emails","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Scheduler","depth":8,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Scheduler","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"API Guide","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"API Guide","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Calendar section","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Calendar","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Meetings section","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Meetings","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Webhooks","depth":8,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Webhooks","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"API guide","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"API guide","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Subscriptions section","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Subscriptions","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Webhooks journal","depth":8,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Webhooks journal","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Overview","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Overview","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Subscriptions section","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Subscriptions","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Journal entries section","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Journal entries","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Snapshots section","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Snapshots","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"English","depth":7,"bounds":{"left":0.43666887,"top":0.9616919,"width":0.026595745,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"English","depth":9,"bounds":{"left":0.4476396,"top":0.9676776,"width":0.015625,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle dark mode","depth":7,"bounds":{"left":0.48853058,"top":0.9632881,"width":0.017287234,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"close","depth":7,"bounds":{"left":0.49983376,"top":0.15722266,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"close","depth":9,"bounds":{"left":0.50382316,"top":0.16280925,"width":0.012632979,"height":0.015961692},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"On this page","depth":10,"bounds":{"left":0.8528923,"top":0.17318435,"width":0.03474069,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"On this page","depth":12,"bounds":{"left":0.85954124,"top":0.17597765,"width":0.028091755,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Make a search request","depth":12,"bounds":{"left":0.8528923,"top":0.19872306,"width":0.082446806,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Make a search request","depth":13,"bounds":{"left":0.8528923,"top":0.2047087,"width":0.049534574,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Searchable CRM objects and engagements","depth":12,"bounds":{"left":0.8528923,"top":0.22426178,"width":0.082446806,"height":0.044692736},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Searchable CRM objects and engagements","depth":13,"bounds":{"left":0.8528923,"top":0.23024741,"width":0.062832445,"height":0.03312051},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Objects","depth":12,"bounds":{"left":0.8528923,"top":0.26895452,"width":0.082446806,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Objects","depth":13,"bounds":{"left":0.85821146,"top":0.27494013,"width":0.01662234,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Engagements","depth":12,"bounds":{"left":0.8528923,"top":0.29449323,"width":0.082446806,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Engagements","depth":13,"bounds":{"left":0.85821146,"top":0.30047885,"width":0.03025266,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Search default searchable properties","depth":12,"bounds":{"left":0.8528923,"top":0.3200319,"width":0.082446806,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Search default searchable properties","depth":13,"bounds":{"left":0.8528923,"top":0.32601756,"width":0.080784574,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Filter search results","depth":12,"bounds":{"left":0.8528923,"top":0.34557062,"width":0.082446806,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Filter search results","depth":13,"bounds":{"left":0.8528923,"top":0.35155627,"width":0.042386968,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Search through associations","depth":12,"bounds":{"left":0.8528923,"top":0.37110934,"width":0.082446806,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Search through associations","depth":13,"bounds":{"left":0.8528923,"top":0.37709498,"width":0.06216755,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Sort search results","depth":12,"bounds":{"left":0.8528923,"top":0.39664805,"width":0.082446806,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sort search results","depth":13,"bounds":{"left":0.8528923,"top":0.40263367,"width":0.04055851,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Paging through results","depth":12,"bounds":{"left":0.8528923,"top":0.42218676,"width":0.082446806,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Paging through results","depth":13,"bounds":{"left":0.8528923,"top":0.42817238,"width":0.04936835,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Limits","depth":12,"bounds":{"left":0.8528923,"top":0.44772545,"width":0.082446806,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Limits","depth":13,"bounds":{"left":0.8528923,"top":0.4537111,"width":0.013297873,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"CRM","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Search the CRM","depth":9,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Search the CRM","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The CRM search endpoints make getting data more efficient by allowing developers to filter, sort, and search across any CRM object type.","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Documentation Index","depth":10,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Documentation Index","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Fetch the complete documentation index at:","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"https://developers.hubspot.com/docs/llms.txt","depth":11,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"https://developers.hubspot.com/docs/llms.txt","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Use this file to discover all available pages before exploring further.","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Use the CRM search endpoints to filter, sort, and search objects, records, and engagements across your CRM. For example, use the endpoints to get a list of contacts in your account, or a list of all open deals. To use these endpoints from an app, a CRM scope is required. Refer to this","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"list of available scopes","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"list of available scopes","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to learn which granular CRM scopes can be used to accomplish your goal.","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Navigate to header Make a search request","depth":9,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"Navigate to header","depth":11,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Make a search request","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"To search your CRM, make a","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"POST","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"request to the object’s search endpoint. CRM search endpoints are constructed using the following format:","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/crm/objects/2026-03/{object}/search","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":". In the request body, you’ll include","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"filters","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"filters","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to narrow your search by CRM property values. For example, the code snippet below would retrieve a list of all contacts that have a specific company email address.","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Report incorrect code","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy the contents from the code block","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Ask AI","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"{","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"filterGroups\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":": [","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"filters\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":": [","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"propertyName\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"email\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"operator\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"CONTAINS_TOKEN\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"value\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"*@hubspot.com\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"]","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"]","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Each object that you search will include a set of","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"default properties","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"default properties","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"that gets returned. For contacts, a search will return","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"createdate","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"email","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"firstname","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"hs_object_id","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"lastmodifieddate","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", and","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"lastname","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":". For example, the above request would return the following response:","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Report incorrect code","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy the contents from the code block","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Ask AI","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"{","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"total\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"results\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":": [","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"id\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"100451\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"properties\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":": {","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"createdate\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"2024-01-17T19:55:04.281Z\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"email\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"testperson@hubspot.com\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"firstname\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"Test\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"hs_object_id\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"100451\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"lastmodifieddate\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"2024-09-11T13:27:39.356Z\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"lastname\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"Person\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"},","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"createdAt\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"2024-01-17T19:55:04.281Z\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"updatedAt\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"2024-09-11T13:27:39.356Z\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"archived\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"false","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"},","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"id\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"57156923994\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"properties\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":": {","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"createdate\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"2024-09-11T18:21:50.012Z\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"email\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"emailmaria@hubspot.com\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"firstname\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"Maria\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"hs_object_id\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"57156923994\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"lastmodifieddate\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"2024-10-21T21:36:02.961Z\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"lastname\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"Johnson (Sample Contact)\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"},","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"createdAt\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"2024-09-11T18:21:50.012Z\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"updatedAt\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"2024-10-21T21:36:02.961Z\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"archived\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"false","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"]","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"To return a specific set of properties, include a","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"properties","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"array in the request body. For example:","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Report incorrect code","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy the contents from the code block","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Ask AI","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"{","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"filterGroups\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":": [","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"filters\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":": [","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"propertyName\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"annualrevenue\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"operator\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"GT\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"value\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"10000000\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"]","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"],","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"properties\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":": [","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"annualrevenue\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"name\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"]","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The response for the above request would look like:","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Report incorrect code","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy the contents from the code block","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Ask AI","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"{","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"total\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"38","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"results\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":": [","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"id\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"2810868468\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"properties\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":": {","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"annualrevenue\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"1000000000\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"createdate\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"2020-01-09T20:11:27.309Z\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"hs_lastmodifieddate\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"2024-09-13T20:23:03.333Z\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"hs_object_id\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"2810868468\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"name\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"Google\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"},","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"createdAt\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"2020-01-09T20:11:27.309Z\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"updatedAt\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"2024-09-13T20:23:03.333Z\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"archived\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"false","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"},","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"id\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"2823023532\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"properties\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":": {","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"annualrevenue\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"10000000000\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"createdate\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"2020-01-13T16:21:08.270Z\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"hs_lastmodifieddate\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"2024-09-13T20:23:03.064Z\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"hs_object_id\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"2823023532\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"name\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"Pepsi\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"},","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"createdAt\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-1893136837287259055
|
-1242580391631814832
|
visual_change
|
accessibility
|
NULL
|
Platform Sprint 3 Q2 - Platform Team - Scrum Board Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
SevenShores\Hubspot\Exceptions\BadRequest: Client error: `POST [URL_WITH_CREDENTIALS]
}
]
}
]
}
Each object that you search will include a set of
default properties
default properties
that gets returned. For contacts, a search will return
createdate
,
email
,
firstname
,
hs_object_id
,
lastmodifieddate
, and
lastname
. For example, the above request would return the following response:
Report incorrect code
Copy the contents from the code block
Ask AI
{
"total"
:
2
,
"results"
: [
{
"id"
:
"100451"
,
"properties"
: {
"createdate"
:
"2024-01-17T19:55:04.281Z"
,
"email"
:
"[EMAIL]"
,
"firstname"
:
"Test"
,
"hs_object_id"
:
"100451"
,
"lastmodifieddate"
:
"2024-09-11T13:27:39.356Z"
,
"lastname"
:
"Person"
},
"createdAt"
:
"2024-01-17T19:55:04.281Z"
,
"updatedAt"
:
"2024-09-11T13:27:39.356Z"
,
"archived"
:
false
},
{
"id"
:
"57156923994"
,
"properties"
: {
"createdate"
:
"2024-09-11T18:21:50.012Z"
,
"email"
:
"[EMAIL]"
,
"firstname"
:
"Maria"
,
"hs_object_id"
:
"57156923994"
,
"lastmodifieddate"
:
"2024-10-21T21:36:02.961Z"
,
"lastname"
:
"Johnson (Sample Contact)"
},
"createdAt"
:
"2024-09-11T18:21:50.012Z"
,
"updatedAt"
:
"2024-10-21T21:36:02.961Z"
,
"archived"
:
false
}
]
}
To return a specific set of properties, include a
properties
array in the request body. For example:
Report incorrect code
Copy the contents from the code block
Ask AI
{
"filterGroups"
: [
{
"filters"
: [
{
"propertyName"
:
"annualrevenue"
,
"operator"
:
"GT"
,
"value"
:
"10000000"
}
]
}
],
"properties"
: [
"annualrevenue"
,
"name"
]
}
The response for the above request would look like:
Report incorrect code
Copy the contents from the code block
Ask AI
{
"total"
:
38
,
"results"
: [
{
"id"
:
"2810868468"
,
"properties"
: {
"annualrevenue"
:
"1000000000"
,
"createdate"
:
"2020-01-09T20:11:27.309Z"
,
"hs_lastmodifieddate"
:
"2024-09-13T20:23:03.333Z"
,
"hs_object_id"
:
"2810868468"
,
"name"
:
"Google"
},
"createdAt"
:
"2020-01-09T20:11:27.309Z"
,
"updatedAt"
:
"2024-09-13T20:23:03.333Z"
,
"archived"
:
false
},
{
"id"
:
"2823023532"
,
"properties"
: {
"annualrevenue"
:
"10000000000"
,
"createdate"
:
"2020-01-13T16:21:08.270Z"
,
"hs_lastmodifieddate"
:
"2024-09-13T20:23:03.064Z"
,
"hs_object_id"
:
"2823023532"
,
"name"
:
"Pepsi"
},
"createdAt"...
|
3765
|
NULL
|
NULL
|
NULL
|
|
3768
|
135
|
43
|
2026-05-07T12:39:55.427333+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-07/1778 /Users/lukas/.screenpipe/data/data/2026-05-07/1778157595427_m1.jpg...
|
Firefox
|
Search the CRM - HubSpot docs — Work
|
True
|
developers.hubspot.com/docs/api-reference/latest/c developers.hubspot.com/docs/api-reference/latest/crm/search-the-crm#limits...
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 3 Q2 - Platform Team - Scrum Board Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
SevenShores\Hubspot\Exceptions\BadRequest: Client error: `POST [URL_WITH_CREDENTIALS]
}
]
}
]
}
Each object that you search will include a set of
default properties
default properties
that gets returned. For contacts, a search will return
createdate
,
email
,
firstname
,
hs_object_id
,
lastmodifieddate
, and
lastname
. For example, the above request would return the following response:
Report incorrect code
Copy the contents from the code block
Ask AI
{
"total"
:
2
,
"results"
: [
{
"id"
:
"100451"
,
"properties"
: {
"createdate"
:
"2024-01-17T19:55:04.281Z"
,
"email"
:
"[EMAIL]"
,
"firstname"
:
"Test"
,
"hs_object_id"
:
"100451"
,
"lastmodifieddate"
:
"2024-09-11T13:27:39.356Z"
,
"lastname"
:
"Person"
},
"createdAt"
:
"2024-01-17T19:55:04.281Z"
,
"updatedAt"
:
"2024-09-11T13:27:39.356Z"
,
"archived"
:
false
},
{
"id"
:
"57156923994"
,
"properties"
: {
"createdate"
:
"2024-09-11T18:21:50.012Z"
,
"email"
:
"[EMAIL]"
,
"firstname"
:
"Maria"
,
"hs_object_id"
:
"57156923994"
,
"lastmodifieddate"
:
"2024-10-21T21:36:02.961Z"
,
"lastname"
:
"Johnson (Sample Contact)"
},
"createdAt"
:
"2024-09-11T18:21:50.012Z"
,
"updatedAt"
:
"2024-10-21T21:36:02.961Z"
,
"archived"
:
false
}
]
}
To return a specific set of properties, include a
properties
array in the request body. For example:
Report incorrect code
Copy the contents from the code block
Ask AI
{
"filterGroups"
: [
{
"filters"
: [
{
"propertyName"
:
"annualrevenue"
,
"operator"
:
"GT"
,
"value"
:
"10000000"
}
]
}
],
"properties"
: [
"annualrevenue"
,
"name"
]
}
The response for the above request would look like:
Report incorrect code
Copy the contents from the code block
Ask AI
{
"total"
:
38
,
"results"
: [
{
"id"
:
"2810868468"
,
"properties"
: {
"annualrevenue"
:
"1000000000"
,
"createdate"
:
"2020-01-09T20:11:27.309Z"
,
"hs_lastmodifieddate"
:
"2024-09-13T20:23:03.333Z"
,
"hs_object_id"
:
"2810868468"
,
"name"
:
"Google"
},
"createdAt"
:
"2020-01-09T20:11:27.309Z"
,
"updatedAt"
:
"2024-09-13T20:23:03.333Z"
,
"archived"
:
false
},
{
"id"
:
"2823023532"
,
"properties"
: {
"annualrevenue"
:
"10000000000"
,
"createdate"
:
"2020-01-13T16:21:08.270Z"
,
"hs_lastmodifieddate"
:
"2024-09-13T20:23:03.064Z"
,
"hs_object_id"
:
"2823023532"
,
"name"
:
"Pepsi"
},
"createdAt"
:
"2020-01-13T16:21:08.270Z"
,
"updatedAt"
:
"2024-09-13T20:23:03.064Z"
,
"archived"
:
false
},
{
"id"
:
"5281147580"
,
"properties"
: {
"annualrevenue"
:
"50000000"
,
"createdate"
:
"2021-02-01T21:17:12.250Z"
,
"hs_lastmodifieddate"
:
"2024-09-13T20:23:03.332Z"
,
"hs_object_id"
:
"5281147580"
,
"name"
:
"CORKCICLE"
},...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SevenShores\\Hubspot\\Exceptions\\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your secondly limit.\",\"errorType\":\"RATE_LIMIT","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SevenShores\\Hubspot\\Exceptions\\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your secondly limit.\",\"errorType\":\"RATE_LIMIT","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Service-Desk - Queues - Platform team - Service space - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Service-Desk - Queues - Platform team - Service space - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Sentry","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sentry","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Pull requests · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Userpilot | Ask Jiminny Report Generated","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Userpilot | Ask Jiminny Report Generated","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Search the CRM - HubSpot docs","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Search the CRM - HubSpot docs","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.16770834,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"bounds":{"left":0.190625,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"bounds":{"left":0.21388888,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.23715279,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.26041666,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Skip to main content","depth":6,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip to main content","depth":7,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"HubSpot docs home page light logo","depth":7,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"HubSpot docs","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"home page","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"2026-03","depth":7,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2026-03","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Open search","depth":7,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Search...","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"⌘","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"K","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle assistant panel","depth":7,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Ask AI","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Ask Docs AI","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Changelog","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Changelog","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Log In","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Log In","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Sign up","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sign up","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Home","depth":7,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Home","depth":8,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Get Started","depth":7,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Get Started","depth":8,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Apps","depth":7,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Apps","depth":8,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"CMS","depth":7,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"CMS","depth":8,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"APIs","depth":7,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"APIs","depth":8,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Developer Tooling","depth":7,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Developer Tooling","depth":8,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Overview","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Overview","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Web and mobile SDKs","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Web and mobile SDKs","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Sunsetted and deprecated APIs","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sunsetted and deprecated APIs","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Error handling","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Error handling","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Account & Settings","depth":8,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Account & Settings","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Account information section","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Account information","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Audit Logs section","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Audit Logs","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Brands section","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Brands","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle IP ranges section","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"IP ranges","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Settings section","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Settings","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"App Management","depth":8,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"App Management","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle App Uninstalls section","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"App Uninstalls","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Feature Flags section","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Feature Flags","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Authentication","depth":8,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Authentication","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"API Guide","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"API Guide","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle OAuth tokens section","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OAuth tokens","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Automation","depth":8,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Automation","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Sequences section","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Sequences","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Workflow actions section","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Workflow actions","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"CMS","depth":8,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"CMS","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Blogs section","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Blogs","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Content audit section","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Content audit","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Domains section","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Domains","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle HubDB section","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"HubDB","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Media Bridge section","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Media Bridge","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Pages section","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Pages","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Site Search section","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Site Search","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Source code section","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Source code","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle URL mappings section","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"URL mappings","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle URL redirects section","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"URL redirects","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Communication preferences","depth":8,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Communication preferences","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"API Guide","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"API Guide","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Status section","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Status","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Conversations","depth":8,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversations","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Overview","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Overview","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Chat Configuration section","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Chat Configuration","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Custom Channels section","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Custom Channels","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Visitor identification section","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Visitor identification","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"CRM","depth":8,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"CRM","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"CRM embed","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"CRM embed","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Search the CRM","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Search the CRM","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Understanding the CRM","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Understanding the CRM","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Using object APIs","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Using object APIs","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Activities section","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Activities","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Associations section","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Associations","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Exports section","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Exports","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Extensions section","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Extensions","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Imports section","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Imports","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Limits Tracking section","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Limits Tracking","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Lists section","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Lists","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Objects section","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Objects","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Owners section","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Owners","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Pipelines section","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Pipelines","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Properties section","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Properties","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Property Validations section","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Property Validations","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Events","depth":8,"bounds":{"left":0.36145833,"top":0.0,"width":0.03125,"height":0.022222223},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Events","depth":9,"bounds":{"left":0.36145833,"top":0.0,"width":0.03125,"height":0.019444445},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"API Guide","depth":10,"bounds":{"left":0.34583333,"top":0.0,"width":0.16145833,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"API Guide","depth":12,"bounds":{"left":0.35694444,"top":0.0,"width":0.046875,"height":0.019444445},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Define events section","depth":10,"bounds":{"left":0.33368057,"top":0.0027777778,"width":0.094444446,"height":0.035555556},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Define events","depth":11,"bounds":{"left":0.35729167,"top":0.011111111,"width":0.0625,"height":0.019444445},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Retrieve events section","depth":10,"bounds":{"left":0.33368057,"top":0.039444443,"width":0.10208333,"height":0.035555556},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Retrieve events","depth":11,"bounds":{"left":0.35729167,"top":0.04777778,"width":0.07013889,"height":0.019444445},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Send event data section","depth":10,"bounds":{"left":0.33368057,"top":0.07611111,"width":0.10729167,"height":0.035555556},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Send event data","depth":11,"bounds":{"left":0.35729167,"top":0.08444444,"width":0.07534722,"height":0.019444445},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Files","depth":8,"bounds":{"left":0.36145833,"top":0.14722222,"width":0.021180555,"height":0.022222223},"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Files","depth":9,"bounds":{"left":0.36145833,"top":0.14888889,"width":0.021180555,"height":0.019444445},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"API Guide","depth":10,"bounds":{"left":0.34583333,"top":0.18055555,"width":0.16145833,"height":0.035555556},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"API Guide","depth":12,"bounds":{"left":0.35694444,"top":0.18888889,"width":0.046875,"height":0.019444445},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Files section","depth":10,"bounds":{"left":0.33368057,"top":0.21722223,"width":0.052430555,"height":0.035555556},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Files","depth":11,"bounds":{"left":0.35729167,"top":0.22555555,"width":0.02048611,"height":0.019444445},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Folders section","depth":10,"bounds":{"left":0.33368057,"top":0.25388888,"width":0.06527778,"height":0.035555556},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Folders","depth":11,"bounds":{"left":0.35729167,"top":0.26222223,"width":0.033333335,"height":0.019444445},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Marketing","depth":8,"bounds":{"left":0.36145833,"top":0.325,"width":0.047916666,"height":0.022222223},"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Marketing","depth":9,"bounds":{"left":0.36145833,"top":0.32666665,"width":0.047916666,"height":0.019444445},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Campaigns section","depth":10,"bounds":{"left":0.33368057,"top":0.35833332,"width":0.084375,"height":0.035555556},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Campaigns","depth":11,"bounds":{"left":0.35729167,"top":0.36666667,"width":0.052430555,"height":0.019444445},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle CTAs section","depth":10,"bounds":{"left":0.33368057,"top":0.395,"width":0.05451389,"height":0.035555556},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"CTAs","depth":11,"bounds":{"left":0.35729167,"top":0.40333334,"width":0.022569444,"height":0.019444445},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Forms section","depth":10,"bounds":{"left":0.33368057,"top":0.43166667,"width":0.060763888,"height":0.035555556},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Forms","depth":11,"bounds":{"left":0.35729167,"top":0.44,"width":0.028819444,"height":0.019444445},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Marketing Emails section","depth":10,"bounds":{"left":0.33368057,"top":0.46833333,"width":0.11111111,"height":0.035555556},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Marketing Emails","depth":11,"bounds":{"left":0.35729167,"top":0.47666666,"width":0.079166666,"height":0.019444445},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Marketing Events section","depth":10,"bounds":{"left":0.33368057,"top":0.505,"width":0.11111111,"height":0.035555556},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Marketing Events","depth":11,"bounds":{"left":0.35729167,"top":0.5133333,"width":0.079166666,"height":0.019444445},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Transactional Emails section","depth":10,"bounds":{"left":0.33368057,"top":0.5416667,"width":0.12604167,"height":0.035555556},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Transactional Emails","depth":11,"bounds":{"left":0.35729167,"top":0.55,"width":0.09409722,"height":0.019444445},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Scheduler","depth":8,"bounds":{"left":0.36145833,"top":0.61277777,"width":0.046875,"height":0.022222223},"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Scheduler","depth":9,"bounds":{"left":0.36145833,"top":0.61444443,"width":0.046875,"height":0.019444445},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"API Guide","depth":10,"bounds":{"left":0.34583333,"top":0.64611113,"width":0.16145833,"height":0.035555556},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"API Guide","depth":12,"bounds":{"left":0.35694444,"top":0.65444446,"width":0.046875,"height":0.019444445},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Calendar section","depth":10,"bounds":{"left":0.33368057,"top":0.68277776,"width":0.07326389,"height":0.035555556},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Calendar","depth":11,"bounds":{"left":0.35729167,"top":0.6911111,"width":0.041319445,"height":0.019444445},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Meetings section","depth":10,"bounds":{"left":0.33368057,"top":0.71944445,"width":0.07361111,"height":0.035555556},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Meetings","depth":11,"bounds":{"left":0.35729167,"top":0.7277778,"width":0.041666668,"height":0.019444445},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Webhooks","depth":8,"bounds":{"left":0.36145833,"top":0.79055554,"width":0.049305554,"height":0.022222223},"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Webhooks","depth":9,"bounds":{"left":0.36145833,"top":0.7922222,"width":0.049305554,"height":0.019444445},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"API guide","depth":10,"bounds":{"left":0.34583333,"top":0.8238889,"width":0.16145833,"height":0.035555556},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"API guide","depth":12,"bounds":{"left":0.35694444,"top":0.8322222,"width":0.04548611,"height":0.019444445},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Subscriptions section","depth":10,"bounds":{"left":0.33368057,"top":0.8605555,"width":0.09375,"height":0.035555556},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Subscriptions","depth":11,"bounds":{"left":0.35729167,"top":0.8688889,"width":0.061805554,"height":0.019444445},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Webhooks journal","depth":8,"bounds":{"left":0.36145833,"top":0.9316667,"width":0.08472222,"height":0.022222223},"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Webhooks journal","depth":9,"bounds":{"left":0.36145833,"top":0.93333334,"width":0.08472222,"height":0.019444445},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Overview","depth":10,"bounds":{"left":0.34583333,"top":0.965,"width":0.16145833,"height":0.035000026},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Overview","depth":12,"bounds":{"left":0.35694444,"top":0.97333336,"width":0.043055557,"height":0.019444445},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Subscriptions section","depth":10,"bounds":{"left":0.33368057,"top":1.0,"width":0.09375,"height":-0.0016666651},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Subscriptions","depth":11,"bounds":{"left":0.35729167,"top":1.0,"width":0.061805554,"height":-0.00999999},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Journal entries section","depth":10,"bounds":{"left":0.33368057,"top":1.0,"width":0.10034722,"height":-0.038333297},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Journal entries","depth":11,"bounds":{"left":0.35729167,"top":1.0,"width":0.068402775,"height":-0.046666622},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle Snapshots section","depth":10,"bounds":{"left":0.33368057,"top":1.0,"width":0.08020833,"height":-0.07500005},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Snapshots","depth":11,"bounds":{"left":0.35729167,"top":1.0,"width":0.04826389,"height":-0.08333337},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"English","depth":7,"bounds":{"left":0.34756944,"top":0.0,"width":0.055555556,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"English","depth":9,"bounds":{"left":0.3704861,"top":0.0,"width":0.03263889,"height":0.019444445},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle dark mode","depth":7,"bounds":{"left":0.45590279,"top":0.0,"width":0.036111113,"height":0.031111112},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"close","depth":7,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"close","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"On this page","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"On this page","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Make a search request","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Make a search request","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Searchable CRM objects and engagements","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Searchable CRM objects and engagements","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Objects","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Objects","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Engagements","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Engagements","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Search default searchable properties","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Search default searchable properties","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Filter search results","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Filter search results","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Search through associations","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Search through associations","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Sort search results","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sort search results","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Paging through results","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Paging through results","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Limits","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Limits","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"CRM","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Search the CRM","depth":9,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Search the CRM","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The CRM search endpoints make getting data more efficient by allowing developers to filter, sort, and search across any CRM object type.","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Documentation Index","depth":10,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Documentation Index","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Fetch the complete documentation index at:","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"https://developers.hubspot.com/docs/llms.txt","depth":11,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"https://developers.hubspot.com/docs/llms.txt","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Use this file to discover all available pages before exploring further.","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Use the CRM search endpoints to filter, sort, and search objects, records, and engagements across your CRM. For example, use the endpoints to get a list of contacts in your account, or a list of all open deals. To use these endpoints from an app, a CRM scope is required. Refer to this","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"list of available scopes","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"list of available scopes","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to learn which granular CRM scopes can be used to accomplish your goal.","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Navigate to header Make a search request","depth":9,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"Navigate to header","depth":11,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Make a search request","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"To search your CRM, make a","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"POST","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"request to the object’s search endpoint. CRM search endpoints are constructed using the following format:","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/crm/objects/2026-03/{object}/search","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":". In the request body, you’ll include","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"filters","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"filters","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to narrow your search by CRM property values. For example, the code snippet below would retrieve a list of all contacts that have a specific company email address.","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Report incorrect code","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy the contents from the code block","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Ask AI","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"{","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"filterGroups\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":": [","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"filters\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":": [","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"propertyName\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"email\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"operator\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"CONTAINS_TOKEN\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"value\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"*@hubspot.com\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"]","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"]","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Each object that you search will include a set of","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"default properties","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"default properties","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"that gets returned. For contacts, a search will return","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"createdate","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"email","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"firstname","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"hs_object_id","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"lastmodifieddate","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", and","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"lastname","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":". For example, the above request would return the following response:","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Report incorrect code","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy the contents from the code block","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Ask AI","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"{","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"total\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"results\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":": [","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"id\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"100451\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"properties\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":": {","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"createdate\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"2024-01-17T19:55:04.281Z\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"email\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"testperson@hubspot.com\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"firstname\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"Test\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"hs_object_id\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"100451\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"lastmodifieddate\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"2024-09-11T13:27:39.356Z\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"lastname\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"Person\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"},","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"createdAt\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"2024-01-17T19:55:04.281Z\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"updatedAt\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"2024-09-11T13:27:39.356Z\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"archived\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"false","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"},","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"id\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"57156923994\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"properties\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":": {","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"createdate\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"2024-09-11T18:21:50.012Z\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"email\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"emailmaria@hubspot.com\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"firstname\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"Maria\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"hs_object_id\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"57156923994\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"lastmodifieddate\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"2024-10-21T21:36:02.961Z\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"lastname\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"Johnson (Sample Contact)\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"},","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"createdAt\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"2024-09-11T18:21:50.012Z\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"updatedAt\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"2024-10-21T21:36:02.961Z\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"archived\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"false","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"]","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"To return a specific set of properties, include a","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"properties","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"array in the request body. For example:","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Report incorrect code","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy the contents from the code block","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Ask AI","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"{","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"filterGroups\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":": [","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"filters\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":": [","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"propertyName\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"annualrevenue\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"operator\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"GT\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"value\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"10000000\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"]","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"],","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"properties\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":": [","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"annualrevenue\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"name\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"]","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The response for the above request would look like:","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Report incorrect code","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy the contents from the code block","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Ask AI","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"{","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"total\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"38","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"results\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":": [","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"id\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"2810868468\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"properties\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":": {","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"annualrevenue\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"1000000000\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"createdate\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"2020-01-09T20:11:27.309Z\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"hs_lastmodifieddate\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"2024-09-13T20:23:03.333Z\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"hs_object_id\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"2810868468\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"name\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"Google\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"},","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"createdAt\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"2020-01-09T20:11:27.309Z\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"updatedAt\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"2024-09-13T20:23:03.333Z\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"archived\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"false","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"},","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"id\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"2823023532\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"properties\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":": {","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"annualrevenue\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"10000000000\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"createdate\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"2020-01-13T16:21:08.270Z\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"hs_lastmodifieddate\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"2024-09-13T20:23:03.064Z\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"hs_object_id\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"2823023532\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"name\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"Pepsi\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"},","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"createdAt\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"2020-01-13T16:21:08.270Z\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"updatedAt\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"2024-09-13T20:23:03.064Z\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"archived\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"false","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"},","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"id\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"5281147580\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"properties\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":": {","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"annualrevenue\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"50000000\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"createdate\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"2021-02-01T21:17:12.250Z\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"hs_lastmodifieddate\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"2024-09-13T20:23:03.332Z\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"hs_object_id\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"5281147580\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"name\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"CORKCICLE\"","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"},","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
5024708308213476948
|
-1242968519253196976
|
visual_change
|
accessibility
|
NULL
|
Platform Sprint 3 Q2 - Platform Team - Scrum Board Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
SevenShores\Hubspot\Exceptions\BadRequest: Client error: `POST [URL_WITH_CREDENTIALS]
}
]
}
]
}
Each object that you search will include a set of
default properties
default properties
that gets returned. For contacts, a search will return
createdate
,
email
,
firstname
,
hs_object_id
,
lastmodifieddate
, and
lastname
. For example, the above request would return the following response:
Report incorrect code
Copy the contents from the code block
Ask AI
{
"total"
:
2
,
"results"
: [
{
"id"
:
"100451"
,
"properties"
: {
"createdate"
:
"2024-01-17T19:55:04.281Z"
,
"email"
:
"[EMAIL]"
,
"firstname"
:
"Test"
,
"hs_object_id"
:
"100451"
,
"lastmodifieddate"
:
"2024-09-11T13:27:39.356Z"
,
"lastname"
:
"Person"
},
"createdAt"
:
"2024-01-17T19:55:04.281Z"
,
"updatedAt"
:
"2024-09-11T13:27:39.356Z"
,
"archived"
:
false
},
{
"id"
:
"57156923994"
,
"properties"
: {
"createdate"
:
"2024-09-11T18:21:50.012Z"
,
"email"
:
"[EMAIL]"
,
"firstname"
:
"Maria"
,
"hs_object_id"
:
"57156923994"
,
"lastmodifieddate"
:
"2024-10-21T21:36:02.961Z"
,
"lastname"
:
"Johnson (Sample Contact)"
},
"createdAt"
:
"2024-09-11T18:21:50.012Z"
,
"updatedAt"
:
"2024-10-21T21:36:02.961Z"
,
"archived"
:
false
}
]
}
To return a specific set of properties, include a
properties
array in the request body. For example:
Report incorrect code
Copy the contents from the code block
Ask AI
{
"filterGroups"
: [
{
"filters"
: [
{
"propertyName"
:
"annualrevenue"
,
"operator"
:
"GT"
,
"value"
:
"10000000"
}
]
}
],
"properties"
: [
"annualrevenue"
,
"name"
]
}
The response for the above request would look like:
Report incorrect code
Copy the contents from the code block
Ask AI
{
"total"
:
38
,
"results"
: [
{
"id"
:
"2810868468"
,
"properties"
: {
"annualrevenue"
:
"1000000000"
,
"createdate"
:
"2020-01-09T20:11:27.309Z"
,
"hs_lastmodifieddate"
:
"2024-09-13T20:23:03.333Z"
,
"hs_object_id"
:
"2810868468"
,
"name"
:
"Google"
},
"createdAt"
:
"2020-01-09T20:11:27.309Z"
,
"updatedAt"
:
"2024-09-13T20:23:03.333Z"
,
"archived"
:
false
},
{
"id"
:
"2823023532"
,
"properties"
: {
"annualrevenue"
:
"10000000000"
,
"createdate"
:
"2020-01-13T16:21:08.270Z"
,
"hs_lastmodifieddate"
:
"2024-09-13T20:23:03.064Z"
,
"hs_object_id"
:
"2823023532"
,
"name"
:
"Pepsi"
},
"createdAt"
:
"2020-01-13T16:21:08.270Z"
,
"updatedAt"
:
"2024-09-13T20:23:03.064Z"
,
"archived"
:
false
},
{
"id"
:
"5281147580"
,
"properties"
: {
"annualrevenue"
:
"50000000"
,
"createdate"
:
"2021-02-01T21:17:12.250Z"
,
"hs_lastmodifieddate"
:
"2024-09-13T20:23:03.332Z"
,
"hs_object_id"
:
"5281147580"
,
"name"
:
"CORKCICLE"
},...
|
3766
|
NULL
|
NULL
|
NULL
|
|
3854
|
138
|
43
|
2026-05-07T12:44:54.917711+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-07/1778 /Users/lukas/.screenpipe/data/data/2026-05-07/1778157894917_m2.jpg...
|
PhpStorm
|
faVsco.js – Hubspot/Service.php
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
A
1
Select All
5190
5190
0
4e3f2289-a3d2-5235-b410-b94ebb547490
4e3f2289-a3d2-5235-b410-b94ebb547490
Umbrella Corp
2
2
0
2
2
0
1212213464
1212213464
Umbrella Corp
430
430
0
579583316
579583316
Umbrella Corp
Umbrella Corp
Umbrella Corp
Umbrella Corp
[PHONE]
[PHONE]
Umbrella Corp
<null>
<null>
Umbrella Corp
<null>
<null>
Umbrella Corp
umbrellacorp.com
umbrellacorp.com
Umbrella Corp
/abae74b8-bfa8-4383-9a7f-89f4bf2bdbb4/avatars/1212213464.png
/abae74b8-bfa8-4383-9a7f-89f4bf2bdbb4/avatars/1212213464.png
Umbrella Corp
<null>
<null>
Umbrella Corp
0
0
0
<null>
<null>
Umbrella Corp
2026-03-30 06:44:25
2026-03-30 06:44:25
Umbrella Corp
2019-02-01 15:39:53
2019-02-01 15:39:53
Umbrella Corp
2026-03-30 06:44:25
2026-03-30 06:44:25
Umbrella Corp
id = 5190
Editor
1 row
Reload Page
Table Result Auto Refresh
Cancel Running Statements
Add Row
Delete Row
Revert Selected
Preview Pending Changes
Submit
Tx: Auto
DDL
Find on Current Page
Table Result Local Filter
Record View
Table Coloring Options
Show Geo Viewer
Show Chart
CSV
Export Data…
Copy to Database…
Compare Data
View as
Show Options Menu
Sync Changes
Hide This Notification
Code changed:
Hide
7
48
1
33
1
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Services\Crm\Hubspot;
use Carbon\Carbon;
use Exception;
use Generator;
use GuzzleHttp\Exception\RequestException;
use Illuminate\Support\Facades\Cache;
use InvalidArgumentException;
use Jiminny\Contracts\Repositories\TeamRepository;
use Jiminny\Contracts\Services\Crm\ClientInterface;
use Jiminny\Contracts\Services\Crm\FetchRelatedActivityInterface;
use Jiminny\Contracts\Services\Crm\LayoutManagementInterface;
use Jiminny\Contracts\Services\Crm\MatchCrmEntitiesInterface;
use Jiminny\Contracts\Services\Crm\Provider\HubspotInterface;
use Jiminny\Contracts\Services\Crm\RemoteEntityLookupInterface;
use Jiminny\Contracts\Services\Crm\RemoteEntityManipulationInterface;
use Jiminny\Contracts\Services\Crm\SavePlaybackLinkToCrmInterface;
use Jiminny\Contracts\Services\Crm\SendSummaryToCrmInterface;
use Jiminny\Contracts\Services\Crm\SettingsInterface;
use Jiminny\Contracts\Services\Crm\SyncCrmEntitiesInterface;
use Jiminny\Contracts\Services\Crm\SyncCrmMetadataInterface;
use Jiminny\Contracts\Services\Crm\VerifyTaskExistsInterface;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\HttpNotFoundException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Account;
use Jiminny\Models\Activity;
use Jiminny\Models\Contact;
use Jiminny\Models\Contracts\ActivityContract;
use Jiminny\Models\Crm\BusinessProcess;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldData;
use Jiminny\Models\Crm\Layout;
use Jiminny\Models\Crm\Profile;
use Jiminny\Models\Lead;
use Jiminny\Models\Opportunity;
use Jiminny\Models\Participant;
use Jiminny\Models\Playbook;
use Jiminny\Models\SocialAccount;
use Jiminny\Models\Stage;
use Jiminny\Models\User;
use Jiminny\Repositories\Crm\CrmEntityRepository;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Repositories\Crm\ProfileRepository;
use Jiminny\Repositories\ParticipantRepository;
use Jiminny\Services\Avatar\ProspectPhotoPathService;
use Jiminny\Services\Crm\BaseService;
use Jiminny\Services\Crm\Hubspot\Actions\SyncArchivedProfilesAction;
use Jiminny\Services\Crm\Hubspot\Fields\ValueNormalizer;
use Jiminny\Services\Crm\Hubspot\ServiceTraits\OpportunitySyncTrait;
use Jiminny\Services\Crm\Hubspot\ServiceTraits\SyncCrmEntitiesTrait;
use Jiminny\Services\Crm\Hubspot\ServiceTraits\SyncFieldsTrait;
use Jiminny\Services\Crm\Hubspot\ServiceTraits\WriteCrmTrait;
use Jiminny\Services\Crm\MatchDomainByEmailInterface;
use Jiminny\Services\Crm\OpportunitySyncStrategyResolver;
use Jiminny\Services\Crm\ResolveCompanyNameByEmailTrait;
use Jiminny\Utils\PlaybackUrlBuilder;
use Sentry;
use SevenShores\Hubspot\Exceptions\BadRequest;
use Throwable;
use UnexpectedValueException;
/**
* @phpstan-type CrmFieldDefinition array{
* name: string,
* label: string,
* description: string,
* type: string,
* fieldType: string,
* hidden: bool,
* showCurrencySymbol: bool,
* options: array<array{
* id: string,
* label: string,
* value?: string,
* }
*/
class Service extends BaseService implements
HubspotInterface,
SyncCrmEntitiesInterface,
SyncCrmMetadataInterface,
SendSummaryToCrmInterface,
MatchDomainByEmailInterface,
SavePlaybackLinkToCrmInterface,
RemoteEntityManipulationInterface,
FetchRelatedActivityInterface,
LayoutManagementInterface,
SettingsInterface,
MatchCrmEntitiesInterface,
RemoteEntityLookupInterface,
VerifyTaskExistsInterface
{
use ResolveCompanyNameByEmailTrait;
use SyncCrmEntitiesTrait;
use WriteCrmTrait;
use SyncFieldsTrait;
use OpportunitySyncTrait;
private const int ENGAGEMENT_BODY_MAX_LENGTH = 65536;
private const string LOG_DATE_FORMAT = 'Y-m-d H:i:s';
private const int BATCH_UPDATE_LIMIT = 100;
private const string TEN_SECONDLY_ROLLING_POLICY = 'TEN_SECONDLY_ROLLING';
private const int TEN_SECONDLY_ROLLING_LIMIT = 10;
private const string CALLS_SEARCH_ENDPOINT = '[URL_WITH_CREDENTIALS] ClientInterface|Client
*/
protected $client;
protected OpportunitySyncStrategyResolver $opportunitySyncStrategyResolver;
protected CrmEntityRepository $crmEntityRepository;
protected ProspectPhotoPathService $prospectPhotoPathService;
private SyncFieldAction $syncFieldAction;
private PayloadBuilder $payloadBuilder;
private SyncRelatedActivityManager $syncRelatedActivityManager;
private SyncArchivedProfilesAction $syncArchivedProfilesAction;
private WebhookSyncBatchProcessor $batchProcessor;
public function __construct(
Client $client,
SyncFieldAction $syncFieldAction,
PayloadBuilder $payloadBuilder,
ProspectPhotoPathService $prospectPhotoPathService,
SyncArchivedProfilesAction $syncArchivedProfilesAction,
WebhookSyncBatchProcessor $batchProcessor,
) {
parent::__construct();
$this->client = $client;
$this->syncFieldAction = $syncFieldAction;
$this->prospectPhotoPathService = $prospectPhotoPathService;
$this->payloadBuilder = $payloadBuilder;
$this->syncArchivedProfilesAction = $syncArchivedProfilesAction;
$this->batchProcessor = $batchProcessor;
$this->opportunitySyncStrategyResolver = app(OpportunitySyncStrategyResolver::class, [
'client' => $this->client,
]);
$this->syncRelatedActivityManager = app(SyncRelatedActivityManager::class, [
'client' => $this->client,
'payloadBuilder' => $this->payloadBuilder,
'logger' => $this->logger,
]);
$this->crmEntityRepository = app(CrmEntityRepository::class);
$this->dealFieldsService = app(DealFieldsService::class);
}
public function getDisplayName(): string
{
return 'HubSpot';
}
protected function getOAuthAccount(User $user): ?SocialAccount
{
// In this case, the Account Owner is always the connection for any API operations.
$owner = $user->team->owner;
return $owner->getSocialAccount(SocialAccount::PROVIDER_HUBSPOT);
}
public function getClient(): Client
{
/** @var Client */
return $this->client;
}
/**
* Convert raw field data into a format compatible with CRM APIs.
*
* @param bool $internal Direction of the conversion.
* True is pulling from CRM, false normalize before sending to CRM.
*/
public function normalizeValue(string $fieldType, string $fieldValue, bool $internal = false): string
{
return ValueNormalizer::normalize(
fieldType: $fieldType,
fieldValue: $fieldValue,
isInbound: $internal,
);
}
/**
* @inheritdoc
*/
public function getDefaultFields(string $activityType): array
{
$fields = [];
if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {
$defaultFields = FieldDefinitions::defaultTaskFields();
// This lazy creates these fields if not already setup.
foreach ($defaultFields as $defaultField) {
$fields[] = $this->config->fields()->firstOrCreate($defaultField);
}
}
return $fields;
}
/**
* @inheritdoc
*/
public function getDefaultActivityField(string $activityType): Field
{
/** @var Field $activityField */
$activityField = $this->config->fields()->where([
'crm_provider_id' => 'activityType',
'object_type' => $activityType,
])->first();
return $activityField;
}
/**
* @inheritdoc
*/
public function getSupportedPlaybookTypes(): array
{
return [Playbook::ACTIVITY_TYPE_TASK];
}
/**
* @inheritdoc
*/
public function getDefaultActivityLayoutFields(string $activityType, string $layoutType): array
{
$fields = [];
if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {
// Outcome should always be provided calls/meetings.
$fieldData = [
[
'crm_provider_id' => $layoutType === Layout::TYPE_SOFTPHONE_SUMMARY ? 'disposition' : 'meetingOutcome',
'object_type' => Field::OBJECT_TASK,
],
];
foreach ($fieldData as $data) {
$field = $this->config->fields()->where($data)->first();
// Only add the field if it is created, which it should be.
if ($field) {
$fields[] = $field;
}
}
}
return $fields;
}
public function getDealInsightsFields(): array
{
return FieldDefinitions::dealInsightsFields();
}
protected function getDefaultFollowupLayoutFields(string $activityType): array
{
$fields = [];
$fieldRepo = app(FieldRepository::class);
$fieldData = FieldDefinitions::followupFieldsFilter();
foreach ($fieldData as $data) {
$field = $fieldRepo->findOneConfigurationFieldByProperties($this->config, $data);
// Only add the field if it is created, which it should be.
if ($field) {
$fields[] = $field;
}
}
return $fields;
}
/**
* @inheritdoc
*/
public function syncField(Field $field): void
{
switch ($field->object_type) {
case Field::OBJECT_ACCOUNT:
$crmField = $this->client->getInstance()->companyProperties()->get($field->crm_provider_id);
break;
case Field::OBJECT_CONTACT:
$crmField = $this->client->getInstance()->contactProperties()->get($field->crm_provider_id);
break;
case Field::OBJECT_OPPORTUNITY:
$crmField = $this->client->getInstance()->dealProperties()->get($field->crm_provider_id);
break;
case Field::OBJECT_TASK:
$this->syncSingleTaskField($field);
return;
default:
return;
}
$this->syncFieldAction->execute($field, $crmField->toArray());
}
/**
* @param array<array{
* id:string,
* label:string,
* value?:string
* }> $options
*
* @throws CrmException
*
* @return FieldData[]
*
*/
public function importPicklistValues(
Field $field,
array $options = [['id' => '', 'label' => '', 'value' => '']],
): array {
if (! empty($options[0]['id']) || ! empty($options[0]['value'])) {
// We already have the options, no need to fetch them again
return $this->importOptions($field, $options);
}
$options = [];
switch ($field->getObjectType()) {
case Field::OBJECT_ACCOUNT:
$options = $this->getClient()->fetchPropertyOptions('company', $field->getCrmProviderId());
break;
case Field::OBJECT_CONTACT:
$options = $this->getClient()->fetchPropertyOptions('contact', $field->getCrmProviderId());
break;
case Field::OBJECT_OPPORTUNITY:
// Hubspot has different endpoint for stages
$options = $this->getClient()->fetchOpportunityFieldOptions($field);
break;
case Field::OBJECT_TASK:
if ($field->getCrmProviderId() === 'disposition') {
$options = $this->getClient()->fetchDispositionFieldOptions();
} elseif (in_array($field->getCrmProviderId(), ['meetingOutcome', 'activityType'])) {
$options = $this->getClient()->fetchMeetingOutcomeFieldOptions($field);
}
break;
default:
$this->logger->warning('Invalid object type', [
'object_type' => $field->getObjectType(),
'field_id' => $field->getId(),
]);
throw new CrmException('Invalid object type');
}
return $this->importOptions($field, $options);
}
/**
* @inheritdoc
*/
public function importStages(?array $types = null, ?string $missingStageName = null): ?Stage
{
$missingStage = null;
try {
// Use the HubSpot API client instead of the SDK crmPipelines() method
$endpoint = self::getDealsPipelinesEndpoint();
$pipelinesResponse = $this->client->getInstance()->getClient()->request('GET', $endpoint);
$pipelines = $pipelinesResponse->data->results;
} catch (RequestException|BadRequest $exception) {
throw $exception;
}
foreach ($pipelines as $pipeline) {
$stages = [];
// We create a business process to contain the pipeline, and store all stages against it.
$p = ResponseNormalize::normalizePipeline($pipeline);
// Create/update business process for this pipeline
$businessProcess = $this->config->businessProcesses()->updateOrCreate([
'crm_provider_id' => $p['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($p['label'], 0, 150),
'type' => BusinessProcess::TYPE_OPPORTUNITY,
'is_selectable' => $p['active'],
]);
// A record type is really a clone of the business process, used to store which record uses which pipeline.
// Create/update record type clone
$this->config->recordTypes()->updateOrCreate([
'crm_provider_id' => $p['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($p['label'], 0, 150),
'is_selectable' => $p['active'],
'business_process_id' => $businessProcess->id ?? null,
]);
// Stages - fetch all existing stages upfront to avoid N+1 queries
$existingStages = $this->config->stages()
->withTrashed()
->where('type', Stage::TYPE_OPPORTUNITY)
->get()
->keyBy('crm_provider_id');
foreach ($p['stages'] as $dealStage) {
$s = ResponseNormalize::normalizeDealStage($dealStage);
/** @var ?Stage $existingStage */
$existingStage = $existingStages->get($s['id']);
// Restore soft-deleted stages that are now active in HubSpot
if ($existingStage?->trashed() && $s['active']) {
$existingStage->restore();
}
// Upsert stage (updates soft-deleted records without restoring them)
$stage = $this->config->stages()->withTrashed()->updateOrCreate([
'crm_provider_id' => $s['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($s['label'], 0, 50),
'label' => mb_strimwidth($s['label'], 0, 191),
'type' => Stage::TYPE_OPPORTUNITY,
'sequence' => $s['displayOrder'],
'is_selectable' => $s['active'],
'probability' => $s['probability'] * 100,
]);
if ($missingStageName === $s['id']) {
$missingStage = $stage;
}
$stages[] = $stage->id;
}
$businessProcess->stages()->sync($stages);
}
return $missingStage;
}
/**
* @inheritdoc
*/
public function syncOrganization(): void
{
try {
$endpoint = '[URL_WITH_CREDENTIALS]
*/
public function find(string $name, array $scopes): array
{
$count = $this->limit ?? 20;
$offset = $this->offset ?? 0;
/** @var array<int, array<string, mixed>> */
return Cache::remember(
key: $this->team->getId() . $name . $count . $offset,
ttl: 300,
callback: function () use ($name, $offset, $count): array {
$data = [];
// Use the new V3 API to find contacts based on additional fields.
foreach (['companies', 'contacts'] as $objectType) {
$endpoint = '[URL_WITH_CREDENTIALS]
*/
public function findOpportunities(?string $crmAccountId, ?string $crmContactId, ?int $userId = null): array
{
$data = [];
$ownerData = [];
$ownerId = null;
if ($crmAccountId === null) {
return $data;
}
if ($userId) {
$profileRepository = app(ProfileRepository::class);
$profile = $profileRepository->findProfileByUserId($this->config, $userId);
$ownerId = $profile instanceof Profile ? $profile->getCrmProviderId() : null;
}
$closedStages = $this->getClosedDealStages();
$payload = $this->payloadBuilder->generateOpportunitiesSearchPayload(
$this->config,
$crmAccountId,
$closedStages,
);
$results = $this->client->getPaginatedData($payload, 'deals');
foreach ($results['results'] as $object) {
$properties = $object['properties'];
$amount = null;
if (empty($properties['amount']) === false) {
$currency = $properties['deal_currency_code'] ?? $this->config->default_currency;
// Values can contain commas and any junk so strip them.
$value = (float) preg_replace('/[^\d.]/', '', $properties['amount']);
$amount = formatCurrency($value, $currency);
}
$businessProcess = $this->config
->businessProcesses()
->where('crm_provider_id', $properties['pipeline'])
->first();
if ($businessProcess === null) {
// Import it.
$stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $properties['dealstage']);
$businessProcess = $this->config
->businessProcesses()
->where('crm_provider_id', $properties['pipeline'])
->first();
} else {
$stage = $businessProcess
->stages()
->where('crm_provider_id', $properties['dealstage'])
->where('type', Stage::TYPE_OPPORTUNITY)
->first();
if ($stage === null) {
// Import it.
$stage = $this->importStages(null, $properties['dealstage']);
}
}
$recordType = null;
if ($businessProcess) {
$recordType = $businessProcess->recordTypes()->first();
}
$isWon = in_array($properties['dealstage'], $closedStages['won']);
$isLost = in_array($properties['dealstage'], $closedStages['lost']);
$record = [
'crmId' => $object['id'],
'name' => $properties['dealname'] ?? 'Unknown Deal',
'value' => $amount,
'won' => $isWon,
'closed' => $isWon || $isLost,
'stage' => [
'id' => $stage?->getUuid() ?? '',
'name' => $stage?->getName() ?? '',
],
];
if ($recordType) {
$record += [
'recordType' => [
'id' => $recordType->id_string,
'name' => $recordType->name,
],
];
}
if ($ownerId && isset($properties['hubspot_owner_id']) && $properties['hubspot_owner_id'] === $ownerId) {
$ownerData[] = $record;
}
$data[] = $record;
}
if (! empty($ownerData)) {
return $ownerData;
}
return $data;
}
/**
* @inheritdoc
*/
public function getTasks(?string $objectType, string $objectId, ?string $opportunityId): array
{
$data = [];
switch ($objectType) {
case 'contact':
$hsObject = 'contact';
break;
case 'account':
$hsObject = 'company';
break;
default:
// This is a hack to prioritise and override a contact/company with a deal.
if ($opportunityId) {
$hsObject = 'deal';
$objectId = $opportunityId;
} else {
throw new InvalidArgumentException('Object type not supported.');
}
}
$engagementTypes = ['meetings', 'tasks'];
foreach ($engagementTypes as $engagementType) {
$payload = $this->payloadBuilder->getLinkToTaskPayload($hsObject, $objectId, $engagementType);
$this->logger->info('[HubSpot] CRM Search requested', [
'request' => $payload,
]);
$engagements = $this->client->getPaginatedData($payload, $engagementType);
foreach ($engagements['results'] as $engagement) {
if ($engagementType == 'meetings') {
$title = $engagement['properties']['hs_meeting_title'] ?? 'Scheduled meeting';
} elseif ($engagementType == 'tasks') {
$title = $engagement['properties']['hs_task_subject'];
} else {
$title = 'Scheduled meeting';
}
$data[] = [
'crmId' => $engagement['id'],
'subject' => $title,
'due' => $engagement['properties']['hs_timestamp'],
'type' => $engagement['properties']['hs_activity_type'] ?? null,
];
}
}
usort($data, function ($item1, $item2) {
return $item2['due'] <=> $item1['due'];
});
return $data;
}
/**
* Try to find CRM Objects using email address
*
* @return null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
* }
*/
public function matchExactlyByEmail(string $email, ?int $userId = null): ?array
{
$contactProperties = [
'email',
'firstname',
'lastname',
'country',
'phone',
'mobilephone',
'jobtitle',
'hubspot_owner_id',
'associatedcompanyid',
'photo',
];
$contact = null;
$account = null;
try {
$hsContact = $this->getClient()->getContactByEmail($email, $contactProperties);
if ($hsContact) {
$contact = $this->importContact($hsContact);
$account = $contact->account;
}
$data = $this->convertCrmData($contact, $account, $userId);
return ! empty(array_filter($data)) ? $data : null;
} catch (BadRequest $e) {
$this->logger->warning('[HubSpot] Search failed', [
'team_id' => $this->team->getId(),
'search_identifier' => $email,
'reason' => $e->getMessage(),
]);
}
return null;
}
public function getDomain(string $email): ?string
{
return $this->getDomainFromEmail($email);
}
/**
* Try to find CRM objects using domain name of the email address
*
* @return null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
* }
*/
public function matchByDomain(string $domain, ?int $userId = null): ?array
{
$companyName = $domain;
// Try to find a company matching their email domain.
$companyProperties = [
'country',
'phone',
'name',
'hs_avatar_filemanager_key',
'industry',
'hubspot_owner_id',
'domain',
];
try {
$hsAccounts = $this->client
->getInstance()
->companies()
->searchByDomain($companyName, $companyProperties);
} catch (Throwable $e) {
$this->logger->info('[HubSpot] Search failed', [
'error' => $e->getMessage(),
'domain' => $domain,
]);
return null;
}
$account = null;
// If there are multiple accounts, don't guess, we'll ask later.
if (\count($hsAccounts->data->results) === 1) {
// Persist this remote object.
$account = $this->syncAccount($hsAccounts->data->results[0]->companyId);
}
$data = $this->convertCrmData(null, $account, $userId);
return ! empty(array_filter($data)) ? $data : null;
}
/**
* @return array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
* }
*/
protected function convertCrmData(?Contact $contact, ?Account $account, ?int $userId = null): array
{
$countryCode = null;
if ($contact && $contact->country_code) {
$countryCode = $contact->country_code;
} elseif ($account && $account->country_code) {
$countryCode = $account->country_code;
}
try {
$hsOpportunities = $this->findOpportunities(
$account ? $account->crm_provider_id : null,
$contact ? $contact->crm_provider_id : null,
$userId
);
} catch (Exception $e) {
$hsOpportunities = [];
}
// If there are multiple opportunities, don't guess, we'll ask later.
$opportunity = null;
$stage = null;
if (! empty($hsOpportunities)) {
// Persist this remote object.
$opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);
$stage = $opportunity?->getStage();
}
return [
null,
$account,
$opportunity,
$contact,
$stage,
$countryCode,
];
}
protected function getCacheKey(string $object, ?int $userId = null): ?string
{
$key = $this->team->getId() . $object;
$keySuffix = $this->getOwnerKeySuffix($userId);
return $key . $keySuffix;
}
private function getOwnerKeySuffix(?int $userId = null): string
{
return $userId === null ? '' : (string) $userId;
}
/**
* @return null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
*}
*/
public function matchByPhone(string $phone, ?string $rawPhoneNumber = null, ?int $userId = null): ?array
{
if (str_contains($phone, '**')) {
return null;
}
// trim all whitespaces if present so the lookup doesn't fail
$phone = str_replace(' ', '', $phone);
// Check if the user is internal.
if ($this->isPhoneNumberOfTeamMember($phone)) {
return null;
}
$response = $this->searchForPhoneNumber($phone);
if (empty($response)) {
return null;
}
// This would ideally importContact instead but the response type differs.
$contact = $this->findAndSyncContact($response['results'][0]['id']);
if (! $contact instanceof Contact) {
return null;
}
$account = $contact->account;
$countryCode = $contact->country_code ?? $account->country_code ?? null;
try {
$hsOpportunities = $this->findOpportunities(
$account?->crm_provider_id,
$contact->crm_provider_id,
$userId
);
} catch (Exception $e) {
$hsOpportunities = [];
}
$opportunity = null;
$stage = null;
try {
if (! empty($hsOpportunities)) {
// Persist this remote object.
$opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);
$stage = $opportunity?->getStage();
}
} catch (Exception $e) {
$this->logger->debug('[HubSpot] Opportunity failed to sync.', [
'reason' => $e->getMessage(),
]);
}
return [
null,
$account,
$opportunity,
$contact,
$stage,
$countryCode,
];
}
private function isPhoneNumberOfTeamMember(string $phone): bool
{
$teamRepository = app(TeamRepository::class);
$user = $teamRepository->findTeamMemberByPhone($this->team, $phone);
if ($user instanceof User) {
return true;
}
return false;
}
private function findAndSyncContact(string $crmId): ?Contact
{
try {
return $this->syncContact($crmId);
} catch (Exception $exception) {
$this->logger->info('[HubSpot] Phone match failed', [
'reason' => $exception->getMessage(),
]);
return null;
}
}
private function hasResults(array $response): bool
{
return isset($response['total']) && is_numeric($response['total']) && $response['total'] > 0;
}
private function searchForPhoneNumber(string $phone): array
{
// Normalizes the provided phone number for the API search.
$normalizedPhone = $this->normalizePhoneNumber($phone);
$payload = $this->payloadBuilder->generatePhoneSearchPayload($normalizedPhone);
$this->logger->info('[HubSpot] Phone match search triggered', [
'phone' => $phone,
'normalizedPhone' => $normalizedPhone,
'payload' => $payload,
]);
$response = $this->handlePhoneSearchRequest($normalizedPhone, $payload);
if (! $this->hasResults($response)) {
$nationalPhone = preg_replace('/\D/', '', phone_national(null, $phone));
$payload = $this->payloadBuilder->generatePhoneSearchPayload($nationalPhone);
$this->logger->info('[HubSpot] Phone match national number search triggered', [
'phone' => $phone,
'nationalPhone' => $nationalPhone,
'payload' => $payload,
]);
$response = $this->handlePhoneSearchRequest($phone, $payload);
}
if (! $this->hasResults($response)) {
$payload = $this->payloadBuilder->generatePhoneSearchPayload($normalizedPhone, true);
$this->logger->info('[HubSpot] Phone match alternative search triggered', [
'phone' => $phone,
'normalizedPhone' => $normalizedPhone,
'payload' => $payload,
]);
$response = $this->handlePhoneSearchRequest($phone, $payload);
}
return $this->hasResults($response) ? $response : [];
}
private function handlePhoneSearchRequest(string $phone, array $payload): array
{
$endpoint = '[URL_WITH_CREDENTIALS] null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
* }
*/
public function matchByName(string $name, ?int $userId = null): ?array
{
// Don't waste time searching for single character strings.
if (\strlen($name) <= 1) {
return null;
}
$cacheKey = $this->getCacheKey($name, $userId);
$result = Cache::remember($cacheKey, 60, function () use ($name, $userId) {
$payload = $this->payloadBuilder->generateSearchContactsByNamePayload(
$name,
$this->getContactFields()
);
$hsContacts = $this->client->getPaginatedData($payload, 'contact');
if (empty($hsContacts['results'])) {
return false;
}
$contact = $this->importContact($hsContacts['results'][0]);
if ($contact === null) {
return false;
}
$account = $contact->account;
$countryCode = $contact->country_code ?? $account->country_code ?? null;
try {
$hsOpportunities = $this->findOpportunities(
$account ? $account->crm_provider_id : null,
$contact->crm_provider_id,
$userId
);
} catch (Exception $e) {
$hsOpportunities = [];
}
$opportunity = null;
$stage = null;
if (! empty($hsOpportunities)) {
// Persist this remote object.
$opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);
$stage = $opportunity?->getStage();
}
return [
null,
$account,
$opportunity,
$contact,
$stage,
$countryCode,
];
});
return is_array($result) ? $result : null;
}
private function convertActivityAssociations(Activity $activity): array
{
return [
'contactIds' => $this->getParticipantsIds($activity),
'companyIds' => $activity->hasAccount() ? [$activity->account->crm_provider_id] : [],
'dealIds' => $activity->hasOpportunity() ? [$activity->opportunity->crm_provider_id] : [],
'ownerIds' => [],
];
}
private function getParticipantsIds(Activity $activity): array
{
$attendees = [];
$participantRepository = app(ParticipantRepository::class);
$participants = $participantRepository->getParticipantsWhoEnteredMeeting($activity);
foreach ($participants as $participant) {
if ($participant->user_id || $participant->isCoach()) {
continue;
}
$contact = $participant->contact()->first();
if ($contact && $contact->crm_provider_id) {
$attendees[] = $contact->crm_provider_id;
} else {
if (! empty($participant->name)) {
$attendeeData = $this->fetchMissingAttendeeInfo($participant);
}
if (! empty($attendeeData['id'])) {
$attendees[] = $attendeeData['id'];
}
}
}
if ($activity->hasContact()) {
$attendees[] = $activity->contact->crm_provider_id;
}
return array_unique($attendees);
}
private function fetchMissingAttendeeInfo(Participant $participant): array
{
// Check if we need to look inside an account context.
$activity = $participant->getActivity();
$companyId = $activity->hasAccount() ? $activity->getAccount()->crm_provider_id : null;
// First check the local data.
/** @var Contact[] $contacts */
$contacts = $this->team->contacts()
->with('account')
->where('name', $participant->name)
->whereNotNull('email')
->get();
foreach ($contacts as $contact) {
// If we have a company in scope, check the contact is associated to it.
if (
$companyId !== null
&& ($contact->account_id === null || $companyId !== $contact->account->crm_provider_id)
) {
continue;
}
return [
'id' => $contact->crm_provider_id,
'email' => $contact->email,
];
}
$payload = $this->generateNameSearchPayload($participant->name, 0, 20);
try {
$response = $this->client->getNewInstance()->crm()->contacts()->searchApi()->doSearch($payload);
// TODO add some logic to choose the most suitable contact if multiple
foreach ($response['results'] as $object) {
$properties = $object['properties'];
if (empty($object['properties']) === false) {
// Check the company matches the contact.
// Todo: Move this check inside the API search.
if ($companyId !== null && $companyId !== $properties['associatedcompanyid']) {
continue;
}
return [
'id' => $object['id'],
'email' => $properties['email'],
];
}
}
} catch (Exception $e) {
$this->logger->warning('[' . $this->getDisplayName() . '] Search failed', [
'teamId' => $this->team->id_string,
'request' => $payload,
'reason' => $e->getMessage(),
]);
}
return [];
}
/**
* Store transcripts as note engagement.
*
* @throws Exception
*/
public function createTranscriptNotes(Activity $activity): void
{
// For HS no need to check if Crm profile - Log Notes field is enabled
// We only check if store_transcript toggle is enabled on crm profile.
$engagement = [
'active' => true,
'ownerId' => $this->profile->crm_provider_id,
'timestamp' => $activity->created_at->tz($activity->user->timezone)->getTimestamp() * 1000,
'type' => 'NOTE',
];
// Generate activity transcription.
$transcriptionData = $this->generateTranscription($activity);
// Truncate Notes with max notes length because transcription text could be very long.
$transcripts = mb_strimwidth($transcriptionData, 0, static::ENGAGEMENT_BODY_MAX_LENGTH);
$metadata = [
'body' => $transcripts,
];
$associations = $this->convertActivityAssociations($activity);
try {
$hsEngagement = $this->client
->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
$this->logCrmEngagementManipulation(self::ACTION_CREATE, $engagement, $metadata, $associations);
$noteId = $hsEngagement->data->engagement->id;
// Store crm logged id in transcription.
$transcription = $activity->getTranscription();
$transcription->crm_activity_id = $noteId;
$transcription->save();
} catch (Exception $e) {
Sentry::captureException($e);
}
}
/*
* @inheritdoc
*/
public function updateRecord(string $objectType, string $objectId, array $data, array $headers = []): void
{
$payload = [
'properties' => $data,
];
try {
switch ($objectType) {
case FieldData::OBJECT_OPPORTUNITY:
$this->client->getNewInstance()->crm()->deals()->basicApi()->update($objectId, $payload);
break;
case FieldData::OBJECT_CONTACT:
$this->client->getNewInstance()->crm()->contacts()->basicApi()->update($objectId, $payload);
break;
case FieldData::OBJECT_ACCOUNT:
$this->client->getNewInstance()->crm()->companies()->basicApi()->update($objectId, $payload);
break;
case FieldData::OBJECT_TASK:
// Endpoint for Engagements not ready
$engagements = [
'type' => 'TASK',
];
$metadata = $data;
$this->client->getInstance()->engagements()->update($objectId, $engagements...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.040226065,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: master<br/>Some incoming commits are not fetched<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8081782,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"bounds":{"left":0.8234708,"top":0.019952115,"width":0.09208777,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"A","depth":4,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":5,"bounds":{"left":0.27027926,"top":1.0,"width":0.0039893617,"height":0.0},"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Select All","depth":4,"bounds":{"left":0.52859044,"top":0.118914604,"width":0.07180851,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"5190","depth":6,"bounds":{"left":0.6007314,"top":0.14046289,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"5190","depth":7,"bounds":{"left":0.6007314,"top":0.14046289,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"0","depth":8,"bounds":{"left":0.27027926,"top":1.0,"width":0.098071806,"height":0.0},"on_screen":false,"value":"0","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"4e3f2289-a3d2-5235-b410-b94ebb547490","depth":6,"bounds":{"left":0.6007314,"top":0.16201118,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"4e3f2289-a3d2-5235-b410-b94ebb547490","depth":7,"bounds":{"left":0.6007314,"top":0.16201118,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.27027926,"top":1.0,"width":0.098071806,"height":0.0},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"2","depth":6,"bounds":{"left":0.6007314,"top":0.18355946,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"2","depth":7,"bounds":{"left":0.6007314,"top":0.18355946,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"0","depth":8,"bounds":{"left":0.27027926,"top":1.0,"width":0.098071806,"height":0.0},"on_screen":false,"value":"0","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"2","depth":6,"bounds":{"left":0.6007314,"top":0.20510775,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"2","depth":7,"bounds":{"left":0.6007314,"top":0.20510775,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"0","depth":8,"bounds":{"left":0.27027926,"top":1.0,"width":0.098071806,"height":0.0},"on_screen":false,"value":"0","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"1212213464","depth":6,"bounds":{"left":0.6007314,"top":0.22665602,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"1212213464","depth":7,"bounds":{"left":0.6007314,"top":0.22665602,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.27027926,"top":1.0,"width":0.098071806,"height":0.0},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"430","depth":6,"bounds":{"left":0.6007314,"top":0.2482043,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"430","depth":7,"bounds":{"left":0.6007314,"top":0.2482043,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"0","depth":8,"bounds":{"left":0.27027926,"top":1.0,"width":0.098071806,"height":0.0},"on_screen":false,"value":"0","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"579583316","depth":6,"bounds":{"left":0.6007314,"top":0.2697526,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"579583316","depth":7,"bounds":{"left":0.6007314,"top":0.2697526,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.27027926,"top":1.0,"width":0.098071806,"height":0.0},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"Umbrella Corp","depth":6,"bounds":{"left":0.6007314,"top":0.29130086,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"Umbrella Corp","depth":7,"bounds":{"left":0.6007314,"top":0.29130086,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.27027926,"top":1.0,"width":0.098071806,"height":0.0},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"661-244-6711","depth":6,"bounds":{"left":0.6007314,"top":0.31284916,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"661-244-6711","depth":7,"bounds":{"left":0.6007314,"top":0.31284916,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.27027926,"top":1.0,"width":0.098071806,"height":0.0},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"<null>","depth":6,"bounds":{"left":0.6007314,"top":0.33439744,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"<null>","depth":7,"bounds":{"left":0.6007314,"top":0.33439744,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.27027926,"top":1.0,"width":0.098071806,"height":0.0},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"<null>","depth":6,"bounds":{"left":0.6007314,"top":0.35594574,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"<null>","depth":7,"bounds":{"left":0.6007314,"top":0.35594574,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.27027926,"top":1.0,"width":0.098071806,"height":0.0},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"umbrellacorp.com","depth":6,"bounds":{"left":0.6007314,"top":0.377494,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"umbrellacorp.com","depth":7,"bounds":{"left":0.6007314,"top":0.377494,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.27027926,"top":1.0,"width":0.098071806,"height":0.0},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"/abae74b8-bfa8-4383-9a7f-89f4bf2bdbb4/avatars/1212213464.png","depth":6,"bounds":{"left":0.6007314,"top":0.3990423,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"/abae74b8-bfa8-4383-9a7f-89f4bf2bdbb4/avatars/1212213464.png","depth":7,"bounds":{"left":0.6007314,"top":0.3990423,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.27027926,"top":1.0,"width":0.098071806,"height":0.0},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"<null>","depth":6,"bounds":{"left":0.6007314,"top":0.42059058,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"<null>","depth":7,"bounds":{"left":0.6007314,"top":0.42059058,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.27027926,"top":1.0,"width":0.098071806,"height":0.0},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"0","depth":6,"bounds":{"left":0.6007314,"top":0.44213888,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"0","depth":7,"bounds":{"left":0.6007314,"top":0.44213888,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"0","depth":8,"bounds":{"left":0.27027926,"top":1.0,"width":0.098071806,"height":0.0},"on_screen":false,"value":"0","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"<null>","depth":6,"bounds":{"left":0.6007314,"top":0.46368715,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"<null>","depth":7,"bounds":{"left":0.6007314,"top":0.46368715,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.27027926,"top":1.0,"width":0.098071806,"height":0.0},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"2026-03-30 06:44:25","depth":6,"bounds":{"left":0.6007314,"top":0.48523542,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"2026-03-30 06:44:25","depth":7,"bounds":{"left":0.6007314,"top":0.48523542,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.27027926,"top":1.0,"width":0.098071806,"height":0.0},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"2019-02-01 15:39:53","depth":6,"bounds":{"left":0.6007314,"top":0.5067837,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"2019-02-01 15:39:53","depth":7,"bounds":{"left":0.6007314,"top":0.5067837,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.27027926,"top":1.0,"width":0.098071806,"height":0.0},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"2026-03-30 06:44:25","depth":6,"bounds":{"left":0.6007314,"top":0.528332,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"2026-03-30 06:44:25","depth":7,"bounds":{"left":0.6007314,"top":0.528332,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.27027926,"top":1.0,"width":0.098071806,"height":0.0},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"id = 5190","depth":4,"bounds":{"left":0.5382314,"top":0.09976058,"width":0.08045213,"height":0.014365523},"on_screen":true,"value":"id = 5190","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"Editor","depth":4,"bounds":{"left":0.63829786,"top":0.09976058,"width":0.34574467,"height":0.014365523},"on_screen":true,"role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"1 row","depth":4,"bounds":{"left":0.5299202,"top":0.075019956,"width":0.017952127,"height":0.017557861},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reload Page","depth":4,"bounds":{"left":0.55019945,"top":0.074221864,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Table Result Auto Refresh","depth":4,"bounds":{"left":0.5588431,"top":0.074221864,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Cancel Running Statements","depth":4,"bounds":{"left":0.5674867,"top":0.074221864,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add Row","depth":4,"bounds":{"left":0.5784575,"top":0.074221864,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Delete Row","depth":4,"bounds":{"left":0.58710104,"top":0.074221864,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Revert Selected","depth":4,"bounds":{"left":0.59574467,"top":0.074221864,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Preview Pending Changes","depth":4,"bounds":{"left":0.6043883,"top":0.074221864,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Submit","depth":4,"bounds":{"left":0.6130319,"top":0.074221864,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Tx: Auto","depth":4,"bounds":{"left":0.62400264,"top":0.074221864,"width":0.024268618,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"DDL","depth":4,"bounds":{"left":0.6505984,"top":0.074221864,"width":0.011303191,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Find on Current Page","depth":4,"bounds":{"left":0.6619016,"top":0.074221864,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Table Result Local Filter","depth":4,"bounds":{"left":0.6705452,"top":0.074221864,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Record View","depth":4,"bounds":{"left":0.67918885,"top":0.074221864,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Table Coloring Options","depth":4,"bounds":{"left":0.6878325,"top":0.074221864,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Show Geo Viewer","depth":4,"bounds":{"left":0.69647604,"top":0.074221864,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Show Chart","depth":4,"bounds":{"left":0.70511967,"top":0.074221864,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"CSV","depth":4,"bounds":{"left":0.921875,"top":0.074221864,"width":0.017287234,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Export Data…","depth":4,"bounds":{"left":0.94148934,"top":0.074221864,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Copy to Database…","depth":4,"bounds":{"left":0.95013297,"top":0.074221864,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Compare Data","depth":4,"bounds":{"left":0.9587766,"top":0.074221864,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"View as","depth":4,"bounds":{"left":0.96974736,"top":0.074221864,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Show Options Menu","depth":4,"bounds":{"left":0.97839093,"top":0.074221864,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"7","depth":4,"bounds":{"left":0.46143618,"top":0.19952115,"width":0.0076462766,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"48","depth":4,"bounds":{"left":0.4710771,"top":0.19952115,"width":0.010305851,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.48337767,"top":0.19952115,"width":0.00731383,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"33","depth":4,"bounds":{"left":0.49268618,"top":0.19952115,"width":0.010305851,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.5049867,"top":0.19952115,"width":0.00731383,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.51396275,"top":0.19792499,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.5212766,"top":0.19792499,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse Carbon\\Carbon;\nuse Exception;\nuse Generator;\nuse GuzzleHttp\\Exception\\RequestException;\nuse Illuminate\\Support\\Facades\\Cache;\nuse InvalidArgumentException;\nuse Jiminny\\Contracts\\Repositories\\TeamRepository;\nuse Jiminny\\Contracts\\Services\\Crm\\ClientInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\FetchRelatedActivityInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\LayoutManagementInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\MatchCrmEntitiesInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\Provider\\HubspotInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\RemoteEntityLookupInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\RemoteEntityManipulationInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SavePlaybackLinkToCrmInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SendSummaryToCrmInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SettingsInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SyncCrmEntitiesInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SyncCrmMetadataInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\VerifyTaskExistsInterface;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\HttpNotFoundException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Account;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Contact;\nuse Jiminny\\Models\\Contracts\\ActivityContract;\nuse Jiminny\\Models\\Crm\\BusinessProcess;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldData;\nuse Jiminny\\Models\\Crm\\Layout;\nuse Jiminny\\Models\\Crm\\Profile;\nuse Jiminny\\Models\\Lead;\nuse Jiminny\\Models\\Opportunity;\nuse Jiminny\\Models\\Participant;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\SocialAccount;\nuse Jiminny\\Models\\Stage;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\Crm\\CrmEntityRepository;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Repositories\\Crm\\ProfileRepository;\nuse Jiminny\\Repositories\\ParticipantRepository;\nuse Jiminny\\Services\\Avatar\\ProspectPhotoPathService;\nuse Jiminny\\Services\\Crm\\BaseService;\nuse Jiminny\\Services\\Crm\\Hubspot\\Actions\\SyncArchivedProfilesAction;\nuse Jiminny\\Services\\Crm\\Hubspot\\Fields\\ValueNormalizer;\nuse Jiminny\\Services\\Crm\\Hubspot\\ServiceTraits\\OpportunitySyncTrait;\nuse Jiminny\\Services\\Crm\\Hubspot\\ServiceTraits\\SyncCrmEntitiesTrait;\nuse Jiminny\\Services\\Crm\\Hubspot\\ServiceTraits\\SyncFieldsTrait;\nuse Jiminny\\Services\\Crm\\Hubspot\\ServiceTraits\\WriteCrmTrait;\nuse Jiminny\\Services\\Crm\\MatchDomainByEmailInterface;\nuse Jiminny\\Services\\Crm\\OpportunitySyncStrategyResolver;\nuse Jiminny\\Services\\Crm\\ResolveCompanyNameByEmailTrait;\nuse Jiminny\\Utils\\PlaybackUrlBuilder;\nuse Sentry;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse Throwable;\nuse UnexpectedValueException;\n\n/**\n * @phpstan-type CrmFieldDefinition array{\n * name: string,\n * label: string,\n * description: string,\n * type: string,\n * fieldType: string,\n * hidden: bool,\n * showCurrencySymbol: bool,\n * options: array<array{\n * id: string,\n * label: string,\n * value?: string,\n * }\n */\nclass Service extends BaseService implements\n HubspotInterface,\n SyncCrmEntitiesInterface,\n SyncCrmMetadataInterface,\n SendSummaryToCrmInterface,\n MatchDomainByEmailInterface,\n SavePlaybackLinkToCrmInterface,\n RemoteEntityManipulationInterface,\n FetchRelatedActivityInterface,\n LayoutManagementInterface,\n SettingsInterface,\n MatchCrmEntitiesInterface,\n RemoteEntityLookupInterface,\n VerifyTaskExistsInterface\n{\n use ResolveCompanyNameByEmailTrait;\n use SyncCrmEntitiesTrait;\n use WriteCrmTrait;\n use SyncFieldsTrait;\n use OpportunitySyncTrait;\n\n private const int ENGAGEMENT_BODY_MAX_LENGTH = 65536;\n\n private const string LOG_DATE_FORMAT = 'Y-m-d H:i:s';\n private const int BATCH_UPDATE_LIMIT = 100;\n private const string TEN_SECONDLY_ROLLING_POLICY = 'TEN_SECONDLY_ROLLING';\n private const int TEN_SECONDLY_ROLLING_LIMIT = 10;\n private const string CALLS_SEARCH_ENDPOINT = 'https://api.hubapi.com/crm/v3/objects/calls/search';\n\n private const string TYPE_NOTE = 'NOTE';\n\n private const string TYPE_MEETING = 'MEETING';\n\n private const string TYPE_CALL = 'CALL';\n\n private const string API_URL = 'https://api.hubapi.com';\n\n // NB: v1 is legacy - v3 is the newest\n private const string ENDPOINT_PIPELINES = '/crm-pipelines/v1/pipelines/';\n private const string PIPELINE_OBJECT_TYPE_DEALS = 'deals';\n\n private const int TASK_VERIFICATION_CACHE_TTL = 86400; // 1 day\n\n /**\n * @var ClientInterface|Client\n */\n protected $client;\n protected OpportunitySyncStrategyResolver $opportunitySyncStrategyResolver;\n protected CrmEntityRepository $crmEntityRepository;\n protected ProspectPhotoPathService $prospectPhotoPathService;\n\n private SyncFieldAction $syncFieldAction;\n private PayloadBuilder $payloadBuilder;\n private SyncRelatedActivityManager $syncRelatedActivityManager;\n private SyncArchivedProfilesAction $syncArchivedProfilesAction;\n private WebhookSyncBatchProcessor $batchProcessor;\n\n public function __construct(\n Client $client,\n SyncFieldAction $syncFieldAction,\n PayloadBuilder $payloadBuilder,\n ProspectPhotoPathService $prospectPhotoPathService,\n SyncArchivedProfilesAction $syncArchivedProfilesAction,\n WebhookSyncBatchProcessor $batchProcessor,\n ) {\n parent::__construct();\n\n $this->client = $client;\n $this->syncFieldAction = $syncFieldAction;\n $this->prospectPhotoPathService = $prospectPhotoPathService;\n $this->payloadBuilder = $payloadBuilder;\n $this->syncArchivedProfilesAction = $syncArchivedProfilesAction;\n $this->batchProcessor = $batchProcessor;\n $this->opportunitySyncStrategyResolver = app(OpportunitySyncStrategyResolver::class, [\n 'client' => $this->client,\n ]);\n $this->syncRelatedActivityManager = app(SyncRelatedActivityManager::class, [\n 'client' => $this->client,\n 'payloadBuilder' => $this->payloadBuilder,\n 'logger' => $this->logger,\n ]);\n $this->crmEntityRepository = app(CrmEntityRepository::class);\n $this->dealFieldsService = app(DealFieldsService::class);\n }\n\n public function getDisplayName(): string\n {\n return 'HubSpot';\n }\n\n protected function getOAuthAccount(User $user): ?SocialAccount\n {\n // In this case, the Account Owner is always the connection for any API operations.\n $owner = $user->team->owner;\n\n return $owner->getSocialAccount(SocialAccount::PROVIDER_HUBSPOT);\n }\n\n public function getClient(): Client\n {\n /** @var Client */\n return $this->client;\n }\n\n /**\n * Convert raw field data into a format compatible with CRM APIs.\n *\n * @param bool $internal Direction of the conversion.\n * True is pulling from CRM, false normalize before sending to CRM.\n */\n public function normalizeValue(string $fieldType, string $fieldValue, bool $internal = false): string\n {\n return ValueNormalizer::normalize(\n fieldType: $fieldType,\n fieldValue: $fieldValue,\n isInbound: $internal,\n );\n }\n\n /**\n * @inheritdoc\n */\n public function getDefaultFields(string $activityType): array\n {\n $fields = [];\n\n if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {\n $defaultFields = FieldDefinitions::defaultTaskFields();\n\n // This lazy creates these fields if not already setup.\n foreach ($defaultFields as $defaultField) {\n $fields[] = $this->config->fields()->firstOrCreate($defaultField);\n }\n }\n\n return $fields;\n }\n\n /**\n * @inheritdoc\n */\n public function getDefaultActivityField(string $activityType): Field\n {\n /** @var Field $activityField */\n $activityField = $this->config->fields()->where([\n 'crm_provider_id' => 'activityType',\n 'object_type' => $activityType,\n ])->first();\n\n return $activityField;\n }\n\n /**\n * @inheritdoc\n */\n public function getSupportedPlaybookTypes(): array\n {\n return [Playbook::ACTIVITY_TYPE_TASK];\n }\n\n /**\n * @inheritdoc\n */\n public function getDefaultActivityLayoutFields(string $activityType, string $layoutType): array\n {\n $fields = [];\n\n if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {\n // Outcome should always be provided calls/meetings.\n $fieldData = [\n [\n 'crm_provider_id' => $layoutType === Layout::TYPE_SOFTPHONE_SUMMARY ? 'disposition' : 'meetingOutcome',\n 'object_type' => Field::OBJECT_TASK,\n ],\n ];\n\n foreach ($fieldData as $data) {\n $field = $this->config->fields()->where($data)->first();\n\n // Only add the field if it is created, which it should be.\n if ($field) {\n $fields[] = $field;\n }\n }\n }\n\n return $fields;\n }\n\n public function getDealInsightsFields(): array\n {\n return FieldDefinitions::dealInsightsFields();\n }\n\n protected function getDefaultFollowupLayoutFields(string $activityType): array\n {\n $fields = [];\n $fieldRepo = app(FieldRepository::class);\n $fieldData = FieldDefinitions::followupFieldsFilter();\n\n foreach ($fieldData as $data) {\n $field = $fieldRepo->findOneConfigurationFieldByProperties($this->config, $data);\n\n // Only add the field if it is created, which it should be.\n if ($field) {\n $fields[] = $field;\n }\n }\n\n return $fields;\n }\n\n /**\n * @inheritdoc\n */\n public function syncField(Field $field): void\n {\n switch ($field->object_type) {\n case Field::OBJECT_ACCOUNT:\n $crmField = $this->client->getInstance()->companyProperties()->get($field->crm_provider_id);\n\n break;\n case Field::OBJECT_CONTACT:\n $crmField = $this->client->getInstance()->contactProperties()->get($field->crm_provider_id);\n\n break;\n case Field::OBJECT_OPPORTUNITY:\n $crmField = $this->client->getInstance()->dealProperties()->get($field->crm_provider_id);\n\n break;\n case Field::OBJECT_TASK:\n $this->syncSingleTaskField($field);\n\n return;\n default:\n return;\n }\n\n $this->syncFieldAction->execute($field, $crmField->toArray());\n }\n\n /**\n * @param array<array{\n * id:string,\n * label:string,\n * value?:string\n * }> $options\n *\n * @throws CrmException\n *\n * @return FieldData[]\n *\n */\n public function importPicklistValues(\n Field $field,\n array $options = [['id' => '', 'label' => '', 'value' => '']],\n ): array {\n if (! empty($options[0]['id']) || ! empty($options[0]['value'])) {\n // We already have the options, no need to fetch them again\n return $this->importOptions($field, $options);\n }\n\n $options = [];\n\n switch ($field->getObjectType()) {\n case Field::OBJECT_ACCOUNT:\n $options = $this->getClient()->fetchPropertyOptions('company', $field->getCrmProviderId());\n\n break;\n\n case Field::OBJECT_CONTACT:\n $options = $this->getClient()->fetchPropertyOptions('contact', $field->getCrmProviderId());\n\n break;\n\n case Field::OBJECT_OPPORTUNITY:\n // Hubspot has different endpoint for stages\n $options = $this->getClient()->fetchOpportunityFieldOptions($field);\n\n break;\n\n case Field::OBJECT_TASK:\n if ($field->getCrmProviderId() === 'disposition') {\n $options = $this->getClient()->fetchDispositionFieldOptions();\n } elseif (in_array($field->getCrmProviderId(), ['meetingOutcome', 'activityType'])) {\n $options = $this->getClient()->fetchMeetingOutcomeFieldOptions($field);\n }\n\n break;\n\n default:\n $this->logger->warning('Invalid object type', [\n 'object_type' => $field->getObjectType(),\n 'field_id' => $field->getId(),\n ]);\n\n throw new CrmException('Invalid object type');\n }\n\n return $this->importOptions($field, $options);\n }\n\n /**\n * @inheritdoc\n */\n public function importStages(?array $types = null, ?string $missingStageName = null): ?Stage\n {\n $missingStage = null;\n\n try {\n // Use the HubSpot API client instead of the SDK crmPipelines() method\n $endpoint = self::getDealsPipelinesEndpoint();\n $pipelinesResponse = $this->client->getInstance()->getClient()->request('GET', $endpoint);\n $pipelines = $pipelinesResponse->data->results;\n } catch (RequestException|BadRequest $exception) {\n throw $exception;\n }\n\n foreach ($pipelines as $pipeline) {\n $stages = [];\n\n // We create a business process to contain the pipeline, and store all stages against it.\n $p = ResponseNormalize::normalizePipeline($pipeline);\n\n // Create/update business process for this pipeline\n $businessProcess = $this->config->businessProcesses()->updateOrCreate([\n 'crm_provider_id' => $p['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($p['label'], 0, 150),\n 'type' => BusinessProcess::TYPE_OPPORTUNITY,\n 'is_selectable' => $p['active'],\n ]);\n\n // A record type is really a clone of the business process, used to store which record uses which pipeline.\n // Create/update record type clone\n $this->config->recordTypes()->updateOrCreate([\n 'crm_provider_id' => $p['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($p['label'], 0, 150),\n 'is_selectable' => $p['active'],\n 'business_process_id' => $businessProcess->id ?? null,\n ]);\n\n // Stages - fetch all existing stages upfront to avoid N+1 queries\n $existingStages = $this->config->stages()\n ->withTrashed()\n ->where('type', Stage::TYPE_OPPORTUNITY)\n ->get()\n ->keyBy('crm_provider_id');\n\n foreach ($p['stages'] as $dealStage) {\n $s = ResponseNormalize::normalizeDealStage($dealStage);\n\n /** @var ?Stage $existingStage */\n $existingStage = $existingStages->get($s['id']);\n\n // Restore soft-deleted stages that are now active in HubSpot\n if ($existingStage?->trashed() && $s['active']) {\n $existingStage->restore();\n }\n\n // Upsert stage (updates soft-deleted records without restoring them)\n $stage = $this->config->stages()->withTrashed()->updateOrCreate([\n 'crm_provider_id' => $s['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($s['label'], 0, 50),\n 'label' => mb_strimwidth($s['label'], 0, 191),\n 'type' => Stage::TYPE_OPPORTUNITY,\n 'sequence' => $s['displayOrder'],\n 'is_selectable' => $s['active'],\n 'probability' => $s['probability'] * 100,\n ]);\n\n if ($missingStageName === $s['id']) {\n $missingStage = $stage;\n }\n\n $stages[] = $stage->id;\n }\n\n $businessProcess->stages()->sync($stages);\n }\n\n return $missingStage;\n }\n\n /**\n * @inheritdoc\n */\n public function syncOrganization(): void\n {\n try {\n $endpoint = 'https://api.hubapi.com/integrations/v1/me';\n $response = $this->client->getInstance()->getClient()->request('get', $endpoint);\n\n $accountData = $response->data;\n $this->config->update(['default_currency' => $accountData->currency]);\n } catch (BadRequest $e) {\n throw new CrmException('Could not sync the organization.', $e->getCode(), $e);\n }\n }\n\n /**\n * @inheritdoc\n *\n * @throws CrmException\n */\n public function syncProfiles(?User $userToSearch = null): ?Profile\n {\n $this->syncArchivedProfilesAction->execute($this->team, $this->client, $this->config);\n\n try {\n $owners = $this->client->getOwners();\n } catch (\\HubSpot\\Client\\Crm\\Owners\\ApiException $e) {\n $this->logger->error('[HubSpot] Could not sync the profiles.', [\n 'team_id' => $this->team->getId(),\n 'reason' => $e->getMessage(),\n ]);\n\n throw new CrmException('Could not sync the profiles.', $e->getCode(), $e);\n }\n\n $profileRepository = app(ProfileRepository::class);\n $teamRepository = app(TeamRepository::class);\n\n foreach ($owners as $owner) {\n if ($owner->getArchived()) {\n // not supposed to fetch archived, but log anyway\n $this->logger->warning('[HubSpot] Found archived owner', [\n 'crm_provider_id' => $owner->getId(),\n 'email' => $owner->getEmail(),\n ]);\n\n continue;\n }\n\n $email = $owner->getEmail();\n if ($email === null) {\n continue;\n }\n\n $user = $teamRepository->findActiveTeamMemberByEmail($this->team, $email);\n\n if (! $user instanceof User) {\n continue;\n }\n\n $profile = $profileRepository->updateOrCreateProfile($user, [\n 'crm_configuration_id' => $this->config->getId(),\n 'crm_provider_id' => $owner->getId(),\n ]);\n\n if ($userToSearch && $userToSearch->getId() === $user->getId()) {\n return $profile;\n }\n }\n\n return null;\n }\n\n private function generateNameSearchPayload(string $name, int $offset, int $limit): array\n {\n $payload = [\n 'query' => $name,\n 'sorts' => [\n [\n 'propertyName' => 'modifieddate',\n 'direction' => 'DESCENDING',\n ],\n ],\n 'properties' => [\n 'email',\n 'firstname',\n 'lastname',\n 'country',\n 'phone',\n 'mobilephone',\n 'jobtitle',\n 'hubspot_owner_id',\n 'associatedcompanyid',\n 'photo',\n 'industry',\n 'name',\n 'company',\n ],\n 'limit' => $limit,\n 'after' => $offset,\n ];\n\n $this->logger->debug('[HubSpot] CRM Search requested', [\n 'request' => $payload,\n ]);\n\n return $payload;\n }\n\n /**\n * @inheritdoc\n */\n public function find(string $name, array $scopes): array\n {\n $count = $this->limit ?? 20;\n $offset = $this->offset ?? 0;\n\n /** @var array<int, array<string, mixed>> */\n return Cache::remember(\n key: $this->team->getId() . $name . $count . $offset,\n ttl: 300,\n callback: function () use ($name, $offset, $count): array {\n $data = [];\n\n // Use the new V3 API to find contacts based on additional fields.\n foreach (['companies', 'contacts'] as $objectType) {\n $endpoint = 'https://api.hubapi.com/crm/v3/objects/' . $objectType . '/search';\n $payload = $this->generateNameSearchPayload($name, $offset, $count);\n $type = $objectType === 'companies' ? 'account' : 'contact';\n\n try {\n $response = $this->client->getInstance()->getClient()->request('POST', $endpoint, [\n 'json' => $payload,\n ]);\n\n // Build mapped list.\n foreach ($response['results'] as $object) {\n $properties = $object['properties'];\n\n $objectName = $this->buildContactName($properties);\n\n $record = [\n 'crmId' => $object['id'],\n // Pass crmUrl to the FE, needed for success message in the extension when you log activity.\n 'crmUrl' => $this->generateProviderUrl($object['id'], $type),\n 'name' => $objectName,\n 'prospectType' => $type,\n 'phoneNumbers' => [],\n ];\n\n if ($type === 'account') {\n $record['industry'] = $properties['industry'] ?? null;\n } else {\n $record['title'] = $properties['jobtitle'] ?? null;\n $record['organization'] = $properties['company'] ?? null;\n }\n\n $countryCode = $this->buildContactCountry($properties);\n $parsedNumber = $this->buildContactPhone($countryCode, $properties);\n\n // Add phone number to record.\n if (! empty($parsedNumber['phone'])) {\n $record['phoneNumbers'][] = [\n 'number' => $parsedNumber['phone'],\n 'nationalFormat' => phone_national($countryCode, $parsedNumber['phone']),\n 'type' => 'phone',\n ];\n }\n\n // Add mobile phone number to record.\n if (! empty($properties['mobilephone'])) {\n $mobileNumber = phone_e164($countryCode, $properties['mobilephone']);\n if ($mobileNumber !== null) {\n $record['phoneNumbers'][] = [\n 'number' => $mobileNumber,\n 'nationalFormat' => phone_national($countryCode, $mobileNumber),\n 'type' => 'mobile',\n ];\n }\n }\n\n $data[] = $record;\n }\n } catch (BadRequest $e) {\n $this->logger->warning('[' . $this->getDisplayName() . '] Search failed', [\n 'teamId' => $this->team->getUuid(),\n 'request' => $payload,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n }\n\n return $data;\n },\n );\n }\n\n\n /**\n * @inheritdoc\n */\n public function findOpportunities(?string $crmAccountId, ?string $crmContactId, ?int $userId = null): array\n {\n $data = [];\n $ownerData = [];\n $ownerId = null;\n\n if ($crmAccountId === null) {\n return $data;\n }\n\n if ($userId) {\n $profileRepository = app(ProfileRepository::class);\n $profile = $profileRepository->findProfileByUserId($this->config, $userId);\n\n $ownerId = $profile instanceof Profile ? $profile->getCrmProviderId() : null;\n }\n\n $closedStages = $this->getClosedDealStages();\n $payload = $this->payloadBuilder->generateOpportunitiesSearchPayload(\n $this->config,\n $crmAccountId,\n $closedStages,\n );\n\n $results = $this->client->getPaginatedData($payload, 'deals');\n\n foreach ($results['results'] as $object) {\n $properties = $object['properties'];\n\n $amount = null;\n if (empty($properties['amount']) === false) {\n $currency = $properties['deal_currency_code'] ?? $this->config->default_currency;\n\n // Values can contain commas and any junk so strip them.\n $value = (float) preg_replace('/[^\\d.]/', '', $properties['amount']);\n $amount = formatCurrency($value, $currency);\n }\n\n $businessProcess = $this->config\n ->businessProcesses()\n ->where('crm_provider_id', $properties['pipeline'])\n ->first();\n\n if ($businessProcess === null) {\n // Import it.\n $stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $properties['dealstage']);\n $businessProcess = $this->config\n ->businessProcesses()\n ->where('crm_provider_id', $properties['pipeline'])\n ->first();\n } else {\n $stage = $businessProcess\n ->stages()\n ->where('crm_provider_id', $properties['dealstage'])\n ->where('type', Stage::TYPE_OPPORTUNITY)\n ->first();\n\n if ($stage === null) {\n // Import it.\n $stage = $this->importStages(null, $properties['dealstage']);\n }\n }\n\n $recordType = null;\n if ($businessProcess) {\n $recordType = $businessProcess->recordTypes()->first();\n }\n\n $isWon = in_array($properties['dealstage'], $closedStages['won']);\n $isLost = in_array($properties['dealstage'], $closedStages['lost']);\n\n $record = [\n 'crmId' => $object['id'],\n 'name' => $properties['dealname'] ?? 'Unknown Deal',\n 'value' => $amount,\n 'won' => $isWon,\n 'closed' => $isWon || $isLost,\n 'stage' => [\n 'id' => $stage?->getUuid() ?? '',\n 'name' => $stage?->getName() ?? '',\n ],\n ];\n\n if ($recordType) {\n $record += [\n 'recordType' => [\n 'id' => $recordType->id_string,\n 'name' => $recordType->name,\n ],\n ];\n }\n\n if ($ownerId && isset($properties['hubspot_owner_id']) && $properties['hubspot_owner_id'] === $ownerId) {\n $ownerData[] = $record;\n }\n\n $data[] = $record;\n }\n\n if (! empty($ownerData)) {\n return $ownerData;\n }\n\n return $data;\n }\n\n /**\n * @inheritdoc\n */\n public function getTasks(?string $objectType, string $objectId, ?string $opportunityId): array\n {\n $data = [];\n switch ($objectType) {\n case 'contact':\n $hsObject = 'contact';\n\n break;\n case 'account':\n $hsObject = 'company';\n\n break;\n default:\n // This is a hack to prioritise and override a contact/company with a deal.\n if ($opportunityId) {\n $hsObject = 'deal';\n $objectId = $opportunityId;\n } else {\n throw new InvalidArgumentException('Object type not supported.');\n }\n }\n\n $engagementTypes = ['meetings', 'tasks'];\n\n foreach ($engagementTypes as $engagementType) {\n $payload = $this->payloadBuilder->getLinkToTaskPayload($hsObject, $objectId, $engagementType);\n\n $this->logger->info('[HubSpot] CRM Search requested', [\n 'request' => $payload,\n ]);\n\n $engagements = $this->client->getPaginatedData($payload, $engagementType);\n\n foreach ($engagements['results'] as $engagement) {\n if ($engagementType == 'meetings') {\n $title = $engagement['properties']['hs_meeting_title'] ?? 'Scheduled meeting';\n } elseif ($engagementType == 'tasks') {\n $title = $engagement['properties']['hs_task_subject'];\n } else {\n $title = 'Scheduled meeting';\n }\n\n $data[] = [\n 'crmId' => $engagement['id'],\n 'subject' => $title,\n 'due' => $engagement['properties']['hs_timestamp'],\n 'type' => $engagement['properties']['hs_activity_type'] ?? null,\n ];\n }\n }\n\n usort($data, function ($item1, $item2) {\n return $item2['due'] <=> $item1['due'];\n });\n\n return $data;\n }\n\n /**\n * Try to find CRM Objects using email address\n *\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n * }\n */\n public function matchExactlyByEmail(string $email, ?int $userId = null): ?array\n {\n $contactProperties = [\n 'email',\n 'firstname',\n 'lastname',\n 'country',\n 'phone',\n 'mobilephone',\n 'jobtitle',\n 'hubspot_owner_id',\n 'associatedcompanyid',\n 'photo',\n ];\n $contact = null;\n $account = null;\n\n try {\n $hsContact = $this->getClient()->getContactByEmail($email, $contactProperties);\n\n if ($hsContact) {\n $contact = $this->importContact($hsContact);\n $account = $contact->account;\n }\n\n $data = $this->convertCrmData($contact, $account, $userId);\n\n return ! empty(array_filter($data)) ? $data : null;\n } catch (BadRequest $e) {\n $this->logger->warning('[HubSpot] Search failed', [\n 'team_id' => $this->team->getId(),\n 'search_identifier' => $email,\n 'reason' => $e->getMessage(),\n ]);\n }\n\n return null;\n }\n\n public function getDomain(string $email): ?string\n {\n return $this->getDomainFromEmail($email);\n }\n\n /**\n * Try to find CRM objects using domain name of the email address\n *\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n * }\n */\n public function matchByDomain(string $domain, ?int $userId = null): ?array\n {\n $companyName = $domain;\n\n // Try to find a company matching their email domain.\n $companyProperties = [\n 'country',\n 'phone',\n 'name',\n 'hs_avatar_filemanager_key',\n 'industry',\n 'hubspot_owner_id',\n 'domain',\n ];\n\n try {\n $hsAccounts = $this->client\n ->getInstance()\n ->companies()\n ->searchByDomain($companyName, $companyProperties);\n } catch (Throwable $e) {\n $this->logger->info('[HubSpot] Search failed', [\n 'error' => $e->getMessage(),\n 'domain' => $domain,\n ]);\n\n return null;\n }\n\n $account = null;\n // If there are multiple accounts, don't guess, we'll ask later.\n if (\\count($hsAccounts->data->results) === 1) {\n // Persist this remote object.\n $account = $this->syncAccount($hsAccounts->data->results[0]->companyId);\n }\n\n $data = $this->convertCrmData(null, $account, $userId);\n\n return ! empty(array_filter($data)) ? $data : null;\n }\n\n /**\n * @return array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n * }\n */\n protected function convertCrmData(?Contact $contact, ?Account $account, ?int $userId = null): array\n {\n $countryCode = null;\n if ($contact && $contact->country_code) {\n $countryCode = $contact->country_code;\n } elseif ($account && $account->country_code) {\n $countryCode = $account->country_code;\n }\n\n try {\n $hsOpportunities = $this->findOpportunities(\n $account ? $account->crm_provider_id : null,\n $contact ? $contact->crm_provider_id : null,\n $userId\n );\n } catch (Exception $e) {\n $hsOpportunities = [];\n }\n\n // If there are multiple opportunities, don't guess, we'll ask later.\n $opportunity = null;\n $stage = null;\n if (! empty($hsOpportunities)) {\n // Persist this remote object.\n $opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);\n $stage = $opportunity?->getStage();\n }\n\n return [\n null,\n $account,\n $opportunity,\n $contact,\n $stage,\n $countryCode,\n ];\n }\n\n protected function getCacheKey(string $object, ?int $userId = null): ?string\n {\n $key = $this->team->getId() . $object;\n $keySuffix = $this->getOwnerKeySuffix($userId);\n\n return $key . $keySuffix;\n }\n\n private function getOwnerKeySuffix(?int $userId = null): string\n {\n return $userId === null ? '' : (string) $userId;\n }\n\n /**\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n *}\n */\n public function matchByPhone(string $phone, ?string $rawPhoneNumber = null, ?int $userId = null): ?array\n {\n if (str_contains($phone, '**')) {\n return null;\n }\n\n // trim all whitespaces if present so the lookup doesn't fail\n $phone = str_replace(' ', '', $phone);\n\n // Check if the user is internal.\n if ($this->isPhoneNumberOfTeamMember($phone)) {\n return null;\n }\n\n $response = $this->searchForPhoneNumber($phone);\n if (empty($response)) {\n return null;\n }\n\n // This would ideally importContact instead but the response type differs.\n $contact = $this->findAndSyncContact($response['results'][0]['id']);\n if (! $contact instanceof Contact) {\n return null;\n }\n\n $account = $contact->account;\n $countryCode = $contact->country_code ?? $account->country_code ?? null;\n\n try {\n $hsOpportunities = $this->findOpportunities(\n $account?->crm_provider_id,\n $contact->crm_provider_id,\n $userId\n );\n } catch (Exception $e) {\n $hsOpportunities = [];\n }\n\n $opportunity = null;\n $stage = null;\n\n try {\n if (! empty($hsOpportunities)) {\n // Persist this remote object.\n $opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);\n $stage = $opportunity?->getStage();\n }\n } catch (Exception $e) {\n $this->logger->debug('[HubSpot] Opportunity failed to sync.', [\n 'reason' => $e->getMessage(),\n ]);\n }\n\n return [\n null,\n $account,\n $opportunity,\n $contact,\n $stage,\n $countryCode,\n ];\n }\n\n private function isPhoneNumberOfTeamMember(string $phone): bool\n {\n $teamRepository = app(TeamRepository::class);\n $user = $teamRepository->findTeamMemberByPhone($this->team, $phone);\n\n if ($user instanceof User) {\n return true;\n }\n\n return false;\n }\n\n private function findAndSyncContact(string $crmId): ?Contact\n {\n try {\n return $this->syncContact($crmId);\n } catch (Exception $exception) {\n $this->logger->info('[HubSpot] Phone match failed', [\n 'reason' => $exception->getMessage(),\n ]);\n\n return null;\n }\n }\n\n private function hasResults(array $response): bool\n {\n return isset($response['total']) && is_numeric($response['total']) && $response['total'] > 0;\n }\n\n private function searchForPhoneNumber(string $phone): array\n {\n // Normalizes the provided phone number for the API search.\n $normalizedPhone = $this->normalizePhoneNumber($phone);\n $payload = $this->payloadBuilder->generatePhoneSearchPayload($normalizedPhone);\n\n $this->logger->info('[HubSpot] Phone match search triggered', [\n 'phone' => $phone,\n 'normalizedPhone' => $normalizedPhone,\n 'payload' => $payload,\n ]);\n\n $response = $this->handlePhoneSearchRequest($normalizedPhone, $payload);\n\n if (! $this->hasResults($response)) {\n $nationalPhone = preg_replace('/\\D/', '', phone_national(null, $phone));\n $payload = $this->payloadBuilder->generatePhoneSearchPayload($nationalPhone);\n\n $this->logger->info('[HubSpot] Phone match national number search triggered', [\n 'phone' => $phone,\n 'nationalPhone' => $nationalPhone,\n 'payload' => $payload,\n ]);\n\n $response = $this->handlePhoneSearchRequest($phone, $payload);\n }\n\n if (! $this->hasResults($response)) {\n $payload = $this->payloadBuilder->generatePhoneSearchPayload($normalizedPhone, true);\n\n $this->logger->info('[HubSpot] Phone match alternative search triggered', [\n 'phone' => $phone,\n 'normalizedPhone' => $normalizedPhone,\n 'payload' => $payload,\n ]);\n\n $response = $this->handlePhoneSearchRequest($phone, $payload);\n }\n\n return $this->hasResults($response) ? $response : [];\n }\n\n private function handlePhoneSearchRequest(string $phone, array $payload): array\n {\n $endpoint = 'https://api.hubapi.com/crm/v3/objects/contacts/search';\n\n try {\n $response = $this->client->getInstance()->getClient()->request(\n 'POST',\n $endpoint,\n ['json' => ($payload)],\n );\n } catch (Exception $exception) {\n $this->logger->info('[HubSpot] Phone match failed', [\n 'phone' => $phone,\n 'reason' => $exception->getMessage(),\n ]);\n\n return [];\n }\n\n $this->logger->info('[HubSpot] Phone match completed', [\n 'phone' => $phone,\n 'response' => $response,\n ]);\n\n return $response->toArray();\n }\n\n private function normalizePhoneNumber(string $phone): string\n {\n return ltrim(phone_e164(null, $phone), '+0');\n }\n\n /**\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n * }\n */\n public function matchByName(string $name, ?int $userId = null): ?array\n {\n // Don't waste time searching for single character strings.\n if (\\strlen($name) <= 1) {\n return null;\n }\n\n $cacheKey = $this->getCacheKey($name, $userId);\n\n $result = Cache::remember($cacheKey, 60, function () use ($name, $userId) {\n $payload = $this->payloadBuilder->generateSearchContactsByNamePayload(\n $name,\n $this->getContactFields()\n );\n\n $hsContacts = $this->client->getPaginatedData($payload, 'contact');\n if (empty($hsContacts['results'])) {\n return false;\n }\n\n $contact = $this->importContact($hsContacts['results'][0]);\n if ($contact === null) {\n return false;\n }\n\n $account = $contact->account;\n $countryCode = $contact->country_code ?? $account->country_code ?? null;\n\n try {\n $hsOpportunities = $this->findOpportunities(\n $account ? $account->crm_provider_id : null,\n $contact->crm_provider_id,\n $userId\n );\n } catch (Exception $e) {\n $hsOpportunities = [];\n }\n\n $opportunity = null;\n $stage = null;\n if (! empty($hsOpportunities)) {\n // Persist this remote object.\n $opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);\n $stage = $opportunity?->getStage();\n }\n\n return [\n null,\n $account,\n $opportunity,\n $contact,\n $stage,\n $countryCode,\n ];\n });\n\n return is_array($result) ? $result : null;\n }\n\n\n private function convertActivityAssociations(Activity $activity): array\n {\n return [\n 'contactIds' => $this->getParticipantsIds($activity),\n 'companyIds' => $activity->hasAccount() ? [$activity->account->crm_provider_id] : [],\n 'dealIds' => $activity->hasOpportunity() ? [$activity->opportunity->crm_provider_id] : [],\n 'ownerIds' => [],\n ];\n }\n\n private function getParticipantsIds(Activity $activity): array\n {\n $attendees = [];\n\n $participantRepository = app(ParticipantRepository::class);\n $participants = $participantRepository->getParticipantsWhoEnteredMeeting($activity);\n foreach ($participants as $participant) {\n if ($participant->user_id || $participant->isCoach()) {\n continue;\n }\n\n $contact = $participant->contact()->first();\n if ($contact && $contact->crm_provider_id) {\n $attendees[] = $contact->crm_provider_id;\n } else {\n if (! empty($participant->name)) {\n $attendeeData = $this->fetchMissingAttendeeInfo($participant);\n }\n if (! empty($attendeeData['id'])) {\n $attendees[] = $attendeeData['id'];\n }\n }\n }\n\n if ($activity->hasContact()) {\n $attendees[] = $activity->contact->crm_provider_id;\n }\n\n return array_unique($attendees);\n }\n\n private function fetchMissingAttendeeInfo(Participant $participant): array\n {\n // Check if we need to look inside an account context.\n $activity = $participant->getActivity();\n $companyId = $activity->hasAccount() ? $activity->getAccount()->crm_provider_id : null;\n\n // First check the local data.\n /** @var Contact[] $contacts */\n $contacts = $this->team->contacts()\n ->with('account')\n ->where('name', $participant->name)\n ->whereNotNull('email')\n ->get();\n\n foreach ($contacts as $contact) {\n // If we have a company in scope, check the contact is associated to it.\n if (\n $companyId !== null\n && ($contact->account_id === null || $companyId !== $contact->account->crm_provider_id)\n ) {\n continue;\n }\n\n return [\n 'id' => $contact->crm_provider_id,\n 'email' => $contact->email,\n ];\n }\n\n $payload = $this->generateNameSearchPayload($participant->name, 0, 20);\n\n try {\n $response = $this->client->getNewInstance()->crm()->contacts()->searchApi()->doSearch($payload);\n\n // TODO add some logic to choose the most suitable contact if multiple\n foreach ($response['results'] as $object) {\n $properties = $object['properties'];\n if (empty($object['properties']) === false) {\n // Check the company matches the contact.\n // Todo: Move this check inside the API search.\n if ($companyId !== null && $companyId !== $properties['associatedcompanyid']) {\n continue;\n }\n\n return [\n 'id' => $object['id'],\n 'email' => $properties['email'],\n ];\n }\n }\n } catch (Exception $e) {\n $this->logger->warning('[' . $this->getDisplayName() . '] Search failed', [\n 'teamId' => $this->team->id_string,\n 'request' => $payload,\n 'reason' => $e->getMessage(),\n ]);\n }\n\n return [];\n }\n\n /**\n * Store transcripts as note engagement.\n *\n * @throws Exception\n */\n public function createTranscriptNotes(Activity $activity): void\n {\n // For HS no need to check if Crm profile - Log Notes field is enabled\n // We only check if store_transcript toggle is enabled on crm profile.\n $engagement = [\n 'active' => true,\n 'ownerId' => $this->profile->crm_provider_id,\n 'timestamp' => $activity->created_at->tz($activity->user->timezone)->getTimestamp() * 1000,\n 'type' => 'NOTE',\n ];\n\n // Generate activity transcription.\n $transcriptionData = $this->generateTranscription($activity);\n\n // Truncate Notes with max notes length because transcription text could be very long.\n $transcripts = mb_strimwidth($transcriptionData, 0, static::ENGAGEMENT_BODY_MAX_LENGTH);\n\n $metadata = [\n 'body' => $transcripts,\n ];\n\n $associations = $this->convertActivityAssociations($activity);\n\n try {\n $hsEngagement = $this->client\n ->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n\n $this->logCrmEngagementManipulation(self::ACTION_CREATE, $engagement, $metadata, $associations);\n\n $noteId = $hsEngagement->data->engagement->id;\n\n // Store crm logged id in transcription.\n $transcription = $activity->getTranscription();\n $transcription->crm_activity_id = $noteId;\n $transcription->save();\n } catch (Exception $e) {\n Sentry::captureException($e);\n }\n }\n\n /*\n * @inheritdoc\n */\n public function updateRecord(string $objectType, string $objectId, array $data, array $headers = []): void\n {\n $payload = [\n 'properties' => $data,\n ];\n\n try {\n switch ($objectType) {\n case FieldData::OBJECT_OPPORTUNITY:\n $this->client->getNewInstance()->crm()->deals()->basicApi()->update($objectId, $payload);\n\n break;\n case FieldData::OBJECT_CONTACT:\n $this->client->getNewInstance()->crm()->contacts()->basicApi()->update($objectId, $payload);\n\n break;\n\n case FieldData::OBJECT_ACCOUNT:\n $this->client->getNewInstance()->crm()->companies()->basicApi()->update($objectId, $payload);\n\n break;\n\n case FieldData::OBJECT_TASK:\n // Endpoint for Engagements not ready\n $engagements = [\n 'type' => 'TASK',\n ];\n $metadata = $data;\n $this->client->getInstance()->engagements()->update($objectId, $engagements, $metadata);\n\n $this->logCrmEngagementManipulation(\n self::ACTION_UPDATE,\n ['crmId' => $objectId],\n $metadata,\n );\n\n break;\n\n default:\n throw new UnexpectedValueException('Unsupported object type \"' . $objectType . '\"');\n }\n } catch (\\HubSpot\\Client\\Crm\\Deals\\ApiException $apiException) {\n $errorMessage = $apiException->getMessage();\n if ($apiException->getResponseBody()) {\n $responseBody = json_decode($apiException->getResponseBody(), true, 512, JSON_THROW_ON_ERROR);\n $errorMessage = $responseBody['message'] ?? $apiException->getMessage();\n }\n\n $this->logger->error(\n '[HubSpot] Update record failed',\n [\n 'objectType' => $objectType,\n 'objectId' => $objectId,\n 'payload' => $payload,\n 'reason' => $errorMessage,\n 'team' => $this->team->getUuid(),\n ]\n );\n\n throw new CrmException($errorMessage);\n }\n }\n\n /*\n * @inheritdoc\n */\n public function getRecord(string $objectType, string $objectId, array $fields = []): array\n {\n switch ($objectType) {\n case FieldData::OBJECT_OPPORTUNITY:\n return $this->client->getInstance()->deals()->getById($objectId)->toArray();\n\n case FieldData::OBJECT_CONTACT:\n return $this->client->getInstance()->contacts()->getById($objectId)->toArray();\n\n case FieldData::OBJECT_ACCOUNT:\n return $this->client->getInstance()->companies()->getById($objectId)->toArray();\n\n case FieldData::OBJECT_TASK:\n return $this->client->getInstance()->engagements()->get($objectId)->toArray();\n\n default:\n throw new UnexpectedValueException('Unsupported object type \"' . $objectType . '\"');\n }\n }\n\n /**\n * @throws BadRequest\n * @throws CrmException\n */\n public function updateStage($crmObject, Stage $stage): void\n {\n $payload = [\n 'properties' => [\n [\n 'name' => 'dealstage',\n 'value' => $stage->crm_provider_id,\n ],\n ],\n ];\n\n try {\n $this->client->getInstance()->deals()->update($crmObject->crm_provider_id, $payload);\n } catch (BadRequest $badRequest) {\n if ($badRequest->getCode() === 403) {\n throw new CrmException(\n \"Sorry, you don't have permission to update this stage.\",\n $badRequest->getCode(),\n $badRequest,\n );\n }\n\n $this->logger->warning('[HubSpot] Stage update failed', [\n 'dealId' => $crmObject->crm_provider_id,\n 'payload' => $payload,\n 'message' => $badRequest->getMessage(),\n ]);\n\n throw $badRequest;\n }\n }\n\n public function generateProviderUrl(string $providerId, string $objectType): ?string\n {\n $url = null;\n $baseUrl = 'https://app.hubspot.com/contacts/' . $this->config->crm_provider_id . '/';\n\n switch ($objectType) {\n case 'account':\n $url = $baseUrl . 'company/' . $providerId;\n\n break;\n\n case 'contact':\n $url = $baseUrl . 'contact/' . $providerId;\n\n break;\n\n case 'opportunity':\n $url = $baseUrl . 'deal/' . $providerId;\n\n break;\n\n case 'task':\n case 'activity':\n return null;\n\n // This should not be deep-linked as per JMNY-3934.\n //$url = $baseUrl.'tasks/list/view/all/?taskId='.$providerId;\n break;\n }\n\n return $url;\n }\n\n public function searchCalls(Carbon $from, Carbon $to, string $activityProvider): array\n {\n $this->logger->info('[HubSpot] Search calls', [\n 'from' => $from->format(self::LOG_DATE_FORMAT),\n 'to' => $to->format(self::LOG_DATE_FORMAT),\n ]);\n\n $calls = [];\n $page = 1;\n\n do {\n try {\n $payload = $this->payloadBuilder->generateGetCallsPayload($from, $to, $activityProvider, $page);\n $response = $this->client->getInstance()->getClient()->request(\n 'POST',\n self::CALLS_SEARCH_ENDPOINT,\n ['json' => ($payload)],\n );\n } catch (Exception $exception) {\n $this->logger->info('[HubSpot] Search calls failed', [\n 'from' => $from->format(self::LOG_DATE_FORMAT),\n 'to' => $to->format(self::LOG_DATE_FORMAT),\n 'reason' => $exception->getMessage(),\n ]);\n $response = null;\n }\n\n $responseResults = empty($response['results']) ? [] : $response['results'];\n $calls = array_merge($calls, $responseResults);\n $page++;\n } while (! empty($responseResults));\n\n return $calls;\n }\n\n public function searchCallsForPeriodByPage(Carbon $from, Carbon $to, int $page, bool $retry = true)\n {\n try {\n $payload = $this->payloadBuilder->generateSearchCallsByPeriodPayload($from, $to, $page);\n $response = $this->client->getInstance()->getClient()->request(\n 'POST',\n self::CALLS_SEARCH_ENDPOINT,\n ['json' => ($payload)],\n );\n } catch (Exception $exception) {\n $this->logger->info('[HubSpot] Search calls for period failed', [\n 'from' => $from->format(self::LOG_DATE_FORMAT),\n 'to' => $to->format(self::LOG_DATE_FORMAT),\n 'reason' => $exception->getMessage(),\n 'retry' => $retry,\n ]);\n\n if ($retry) {\n sleep(1);\n\n return $this->searchCallsForPeriodByPage($from, $to, $page, false);\n }\n $response = null;\n }\n\n return $response;\n }\n\n public function searchCallsForPeriod(Carbon $from, Carbon $to): Generator\n {\n $this->logger->info('[HubSpot] Search calls for period', [\n 'from' => $from->format(self::LOG_DATE_FORMAT),\n 'to' => $to->format(self::LOG_DATE_FORMAT),\n ]);\n\n $page = 1;\n\n do {\n $response = $this->searchCallsForPeriodByPage($from, $to, $page);\n\n $responseResults = empty($response['results']) ? [] : $response['results'];\n\n $associationContacts = $this->getAssociationDataForCollection($responseResults, 'calls', 'contacts');\n $associationCompanies = $this->getAssociationDataForCollection($responseResults, 'calls', 'companies');\n $associationDeals = $this->getAssociationDataForCollection($responseResults, 'calls', 'deals');\n\n foreach ($responseResults as $call) {\n $call['associations'] = [\n 'contacts' => $this->importAssociationData($call, $associationContacts),\n 'companies' => $this->importAssociationData($call, $associationCompanies),\n 'deals' => $this->importAssociationData($call, $associationDeals),\n ];\n\n yield $call;\n }\n $page++;\n } while (! empty($responseResults));\n }\n\n public function getCall(string $callId): array\n {\n $this->logger->info('[HubSpot] Get call', [\n 'call_id' => $callId,\n ]);\n\n $searchAttributes = $this->payloadBuilder->getSearchCallAttributes();\n $endpoint = sprintf(\n 'https://api.hubapi.com/crm/v3/objects/calls/%s',\n $callId,\n );\n\n try {\n $response = $this->client->getInstance()->getClient()->request(\n 'GET',\n $endpoint,\n [],\n sprintf(\n 'properties=%s&associations=contacts,companies,deals',\n implode(',', $searchAttributes),\n ),\n );\n } catch (Exception $exception) {\n $this->logger->info('[HubSpot] Get call failed', [\n 'call_id' => $callId,\n 'reason' => $exception->getMessage(),\n ]);\n $response = null;\n }\n\n return empty($response) ? [] : $response->toArray();\n }\n\n public function bulkAddPlaybackURLToDescription(array $crmUpdateData): array\n {\n $crmUpdateBatches = array_chunk($crmUpdateData, self::BATCH_UPDATE_LIMIT);\n\n $updatedCrmIds = [];\n\n foreach ($crmUpdateBatches as $crmBatch) {\n $payload = $this->payloadBuilder->generatePlaybackAddUrlBatchPayload($crmBatch);\n $updateSuccess = $this->bulkAddPlaybackURLToDescriptionRequest($payload);\n if ($updateSuccess) {\n $updatedCrmIds = array_merge($updatedCrmIds, array_column($crmBatch, 'crm_id'));\n }\n }\n\n return $updatedCrmIds;\n }\n\n private function bulkAddPlaybackURLToDescriptionRequest(array $payload, bool $retry = true): bool\n {\n try {\n $this->client->getNewInstance()->crm()->objects()->batchApi()->update('calls', $payload);\n\n return true;\n } catch (\\HubSpot\\Client\\Crm\\Objects\\ApiException $e) {\n $response = json_decode($e->getResponseBody(), true);\n $retryAfter =\n isset($response['policyName'])\n && $response['policyName'] == self::TEN_SECONDLY_ROLLING_POLICY\n ? self::TEN_SECONDLY_ROLLING_LIMIT\n : 1;\n } catch (Exception $e) {\n $retryAfter = 1;\n }\n\n $this->logger->warning('[HubSpot] Bulk add playback url to CRM failed', [\n 'reason' => $e->getMessage(),\n 'retry' => $retry,\n ]);\n\n if ($retry) {\n sleep($retryAfter);\n\n return $this->bulkAddPlaybackURLToDescriptionRequest($payload, false);\n }\n\n return false;\n }\n\n /**\n * Sometimes we have secondly rate limit error, then retry request after 1 second\n */\n public function searchCallByRecordingURLToken(string $playbackURLToken, bool $retry = true): array\n {\n $endpoint = 'https://api.hubapi.com/crm/v3/objects/calls/search';\n $payload = $this->payloadBuilder->generateSearchCallByTokenPayload($playbackURLToken);\n\n $this->logger->info('[HubSpot] CRM Search by playback URL token requested', [\n 'request' => $payload,\n ]);\n\n try {\n $response = $this->client->getInstance()->getClient()->request('POST', $endpoint, ['json' => ($payload)]);\n } catch (Exception $exception) {\n $this->logger->info('[HubSpot] Search by playback URL token failed', [\n 'playbackURLToken' => $playbackURLToken,\n 'reason' => $exception->getMessage(),\n 'retry' => $retry,\n ]);\n\n if ($retry) {\n sleep(1);\n\n return $this->searchCallByRecordingURLToken($playbackURLToken, false);\n }\n\n return [];\n }\n\n return empty($response['results']) ? [] : $response['results'][0];\n }\n\n /**\n * Generate transcription for the activity.\n */\n private function generateTranscription(Activity $activity): string\n {\n if (! $this->config->store_transcript) {\n // If sending transcription to activity toggle is disabled\n return '';\n }\n\n $transcriptionSegments = $this->transcriptionService->findTranscriptionByActivity($activity);\n\n if ($transcriptionSegments->isEmpty()) {\n return '';\n }\n\n $transcription = sprintf(\n '<p><strong>Transcript for %s</strong></p><p></p>',\n $activity->title ?? $activity->activity_title,\n );\n\n $roomOwnerParticipant = $activity->findParticipantRoomOwner();\n $roomOwnerParticipantId = $roomOwnerParticipant !== null\n ? $roomOwnerParticipant->getId()\n : null;\n\n\n $transcription .= $transcriptionSegments\n ->map(static function (array $transcriptionSegment) use ($roomOwnerParticipantId): string {\n $isOrganiser = $roomOwnerParticipantId === $transcriptionSegment['participantId']\n && $roomOwnerParticipantId !== null;\n $transcriptColor = $isOrganiser ? '#000000' : '#f0415a';\n\n return sprintf(\n '<span style=\"color: %s;\">%s | </span>%s',\n $transcriptColor,\n $transcriptionSegment['formattedStartsAt'],\n $transcriptionSegment['transcript'],\n );\n })\n ->implode('<br />');\n\n return $transcription;\n }\n\n /**\n * @param array<array{\n * id: string,\n * label: string,\n * value?: string,\n * }> $options\n *\n * @return FieldData[]\n */\n private function importOptions(Field $field, array $options): array\n {\n $fieldValues = [];\n $values = [];\n $sequence = 0;\n\n foreach ($options as $option) {\n $values[] = [\n 'value' => $option['value'] ?? $option['id'],\n 'label' => substr($option['label'], 0, 255),\n 'sequence' => $sequence++,\n ];\n }\n\n $fieldsToPurge = $field->values()->get()->pluck('value')->toArray();\n\n foreach ($values as $value) {\n $value['value'] = substr($value['value'], 0, 255);\n $fieldValues[] = $field->values()->updateOrCreate([\n 'value' => $value['value'],\n ], $value);\n\n // Remove this value from the ones we are going to purge.\n if (($key = array_search($value['value'], $fieldsToPurge, false)) !== false) {\n unset($fieldsToPurge[$key]);\n }\n }\n\n // Delete the old values that are no longer used.\n $field->values()->whereIn('value', $fieldsToPurge)->delete();\n\n return $fieldValues;\n }\n\n public function saveTranscriptionSummaryAsNote(\n ActivityContract $activity,\n string $title,\n string $body,\n ?string $objectId,\n ?NoteObject $noteObject = null,\n ): ?string {\n if ($noteObject === null || $objectId === null) {\n return null;\n }\n\n /** @var User $user */\n $user = $activity->getUser();\n\n $profile = $this->assignCrmOwner($user, $activity);\n if (! $profile instanceof Profile) {\n return null;\n }\n\n $timestamp = Carbon::now($user->getTimezone())->getTimestamp() * 1000;\n $engagement = [\n 'active' => true,\n 'ownerId' => $profile->getAttribute('crm_provider_id'),\n 'timestamp' => $timestamp,\n 'type' => 'NOTE',\n ];\n\n // Truncate Notes with max notes length because transcription text could be very long.\n $body = mb_strimwidth($body, 0, self::ENGAGEMENT_BODY_MAX_LENGTH);\n $metadata = [\n 'body' => $body,\n ];\n\n $associations = $this->convertActivityAssociations($activity);\n\n try {\n $hsActivityId = $this->client->createNote(\n body: $body,\n ownerId: $profile->getCrmProviderId(),\n timestamp: $timestamp,\n objectId: $objectId,\n noteObject: $noteObject,\n );\n\n $this->logCrmEngagementManipulation(self::ACTION_CREATE, $engagement, $metadata, $associations);\n\n $this->logger->info('[HubSpot] Saving Transcription Summary as Note', [\n 'activity' => $activity->getUuid(),\n 'crmActivity' => $hsActivityId,\n ]);\n\n return $hsActivityId;\n } catch (Exception $e) {\n Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function attachSummaryToActivity(ActivityContract $activity, string $summaryTitle, string $summaryContents): bool\n {\n $this->logger->info('[HubSpot] Attaching summary to activity', [\n 'activity' => $activity->getUuid(),\n 'summary_content' => $summaryContents,\n ]);\n\n if (! $activity instanceof Activity) {\n throw new InvalidArgumentException('Expected instance of Activity');\n }\n\n $summary = '<p><strong>' . $summaryTitle . '</strong></p>';\n $summary .= '<p>' . $summaryContents . '</p>';\n $metadata = $this->buildMetadataForSummaryUpdate($activity, $summary);\n\n try {\n $type = $this->matchActivityEngagementType($activity);\n $engagement = ['type' => $type];\n\n $this->client->updateEngagement($activity->getCrmProviderId(), $engagement, $metadata);\n } catch (Exception $e) {\n $this->logger->warning('[HubSpot] Update summary failed', [\n 'activity' => $activity->getUuid(),\n 'reason' => $e->getMessage(),\n ]);\n\n return false;\n }\n\n $this->logCrmEngagementManipulation(\n self::ACTION_UPDATE,\n ['crmId' => $activity->getCrmProviderId()],\n $metadata,\n );\n\n return true;\n }\n\n private function buildMetadataForSummaryUpdate(Activity $activity, string $summary): array\n {\n $descriptionField = $activity->getType() === Activity::TYPE_CONFERENCE ? 'internalMeetingNotes' : 'body';\n $engagement = $this->client->getEngagementData($activity->getCrmProviderId());\n // Meeting without internalMeetingNotes might mean it just does not have any notes;\n $description = $engagement['metadata'][$descriptionField] ?? null;\n\n if (empty($description)) {\n $data = $summary;\n } else {\n // avoid playbook url link to Jiminny being sent twice in the activity description\n $targetUrl = PlaybackUrlBuilder::build($activity);\n\n if (str_contains($description, $targetUrl)) {\n $jiminnyUrl = '<p><a href=\"' . $targetUrl . '\" title=\"Play at Jiminny\">Play at Jiminny</a></p>';\n $summary = str_replace($jiminnyUrl, '', $summary);\n\n $this->logger->info('[HubSpot] Summary modified', [\n 'activity' => $activity->getUuid(),\n 'target_url' => $jiminnyUrl,\n 'modified_summary_content' => $summary,\n ]);\n }\n\n $data = $description . '<p></p>' . $summary;\n }\n\n return [\n $descriptionField => $data,\n ];\n }\n\n public function fetchAndAssociateRelatedActivity(Activity $activity): ?Activity\n {\n return $this->syncRelatedActivityManager->fetchAndAssociateRelatedActivity($activity);\n }\n\n public function fetchRelatedActivity(Activity $activity): array\n {\n return [];\n }\n\n public function getDealsInBulk(array $dealIds): array\n {\n $payload = $this->payloadBuilder->getDealsInBulkPayload($dealIds);\n\n return $this->client->getPaginatedData($payload, 'deals');\n }\n\n /**\n * Extract deal IDs from HubSpot search response.\n *\n * @param array $hubspotResponse The raw HubSpot search API response.\n * @param bool $includeArchived Whether to include archived deals (default: false).\n *\n * @return string[] Array of deal IDs as strings.\n */\n public function extractDealIds(array $hubspotResponse, bool $includeArchived = false): array\n {\n if (empty($hubspotResponse['results'])) {\n return [];\n }\n\n return array_values(\n array_map(\n fn ($deal) => $deal['id'],\n array_filter(\n $hubspotResponse['results'],\n fn ($deal) => $includeArchived || empty($deal['archived'])\n )\n )\n );\n }\n\n public function matchActivityEngagementType(Activity $activity): string\n {\n return match ($activity->getType()) {\n Activity::TYPE_CONFERENCE => self::TYPE_MEETING,\n Activity::TYPE_SOFTPHONE, Activity::TYPE_SOFTPHONE_INBOUND => self::TYPE_CALL,\n default => self::TYPE_NOTE,\n };\n }\n\n private function assignCrmOwner(User $user, ActivityContract $activity): ?Profile\n {\n $profile = $user->getProfile();\n if ($profile instanceof Profile) {\n return $profile;\n }\n\n $this->logger->info('[HubSpot] Unable to save summary. No profile', [\n 'activity' => $activity->getUuid(),\n ]);\n\n return null;\n }\n\n private static function getDealsPipelinesEndpoint(): string\n {\n return self::API_URL . self::ENDPOINT_PIPELINES . self::PIPELINE_OBJECT_TYPE_DEALS;\n }\n\n public function verifyTaskExists(Activity $activity): bool\n {\n $crmProviderId = $activity->getCrmProviderId();\n $cacheKey = \"crm_task_exists:{$this->config->getId()}:$crmProviderId\";\n\n return Cache::remember($cacheKey, self::TASK_VERIFICATION_CACHE_TTL, function () use ($crmProviderId) {\n try {\n $engagement = $this->client->getEngagementData($crmProviderId);\n\n return ! empty($engagement);\n } catch (HttpNotFoundException|BadRequest) {\n // Engagement not found in CRM - this is expected and permanent\n $this->logger->info('[Hubspot] Engagement not found during verification', [\n 'engagement_id' => $crmProviderId,\n 'config_id' => $this->config->getId(),\n ]);\n\n return false;\n }\n // Let other exceptions (network errors, rate limits, etc.) bubble up for retry\n });\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse Carbon\\Carbon;\nuse Exception;\nuse Generator;\nuse GuzzleHttp\\Exception\\RequestException;\nuse Illuminate\\Support\\Facades\\Cache;\nuse InvalidArgumentException;\nuse Jiminny\\Contracts\\Repositories\\TeamRepository;\nuse Jiminny\\Contracts\\Services\\Crm\\ClientInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\FetchRelatedActivityInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\LayoutManagementInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\MatchCrmEntitiesInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\Provider\\HubspotInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\RemoteEntityLookupInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\RemoteEntityManipulationInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SavePlaybackLinkToCrmInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SendSummaryToCrmInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SettingsInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SyncCrmEntitiesInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SyncCrmMetadataInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\VerifyTaskExistsInterface;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\HttpNotFoundException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Account;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Contact;\nuse Jiminny\\Models\\Contracts\\ActivityContract;\nuse Jiminny\\Models\\Crm\\BusinessProcess;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldData;\nuse Jiminny\\Models\\Crm\\Layout;\nuse Jiminny\\Models\\Crm\\Profile;\nuse Jiminny\\Models\\Lead;\nuse Jiminny\\Models\\Opportunity;\nuse Jiminny\\Models\\Participant;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\SocialAccount;\nuse Jiminny\\Models\\Stage;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\Crm\\CrmEntityRepository;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Repositories\\Crm\\ProfileRepository;\nuse Jiminny\\Repositories\\ParticipantRepository;\nuse Jiminny\\Services\\Avatar\\ProspectPhotoPathService;\nuse Jiminny\\Services\\Crm\\BaseService;\nuse Jiminny\\Services\\Crm\\Hubspot\\Actions\\SyncArchivedProfilesAction;\nuse Jiminny\\Services\\Crm\\Hubspot\\Fields\\ValueNormalizer;\nuse Jiminny\\Services\\Crm\\Hubspot\\ServiceTraits\\OpportunitySyncTrait;\nuse Jiminny\\Services\\Crm\\Hubspot\\ServiceTraits\\SyncCrmEntitiesTrait;\nuse Jiminny\\Services\\Crm\\Hubspot\\ServiceTraits\\SyncFieldsTrait;\nuse Jiminny\\Services\\Crm\\Hubspot\\ServiceTraits\\WriteCrmTrait;\nuse Jiminny\\Services\\Crm\\MatchDomainByEmailInterface;\nuse Jiminny\\Services\\Crm\\OpportunitySyncStrategyResolver;\nuse Jiminny\\Services\\Crm\\ResolveCompanyNameByEmailTrait;\nuse Jiminny\\Utils\\PlaybackUrlBuilder;\nuse Sentry;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse Throwable;\nuse UnexpectedValueException;\n\n/**\n * @phpstan-type CrmFieldDefinition array{\n * name: string,\n * label: string,\n * description: string,\n * type: string,\n * fieldType: string,\n * hidden: bool,\n * showCurrencySymbol: bool,\n * options: array<array{\n * id: string,\n * label: string,\n * value?: string,\n * }\n */\nclass Service extends BaseService implements\n HubspotInterface,\n SyncCrmEntitiesInterface,\n SyncCrmMetadataInterface,\n SendSummaryToCrmInterface,\n MatchDomainByEmailInterface,\n SavePlaybackLinkToCrmInterface,\n RemoteEntityManipulationInterface,\n FetchRelatedActivityInterface,\n LayoutManagementInterface,\n SettingsInterface,\n MatchCrmEntitiesInterface,\n RemoteEntityLookupInterface,\n VerifyTaskExistsInterface\n{\n use ResolveCompanyNameByEmailTrait;\n use SyncCrmEntitiesTrait;\n use WriteCrmTrait;\n use SyncFieldsTrait;\n use OpportunitySyncTrait;\n\n private const int ENGAGEMENT_BODY_MAX_LENGTH = 65536;\n\n private const string LOG_DATE_FORMAT = 'Y-m-d H:i:s';\n private const int BATCH_UPDATE_LIMIT = 100;\n private const string TEN_SECONDLY_ROLLING_POLICY = 'TEN_SECONDLY_ROLLING';\n private const int TEN_SECONDLY_ROLLING_LIMIT = 10;\n private const string CALLS_SEARCH_ENDPOINT = 'https://api.hubapi.com/crm/v3/objects/calls/search';\n\n private const string TYPE_NOTE = 'NOTE';\n\n private const string TYPE_MEETING = 'MEETING';\n\n private const string TYPE_CALL = 'CALL';\n\n private const string API_URL = 'https://api.hubapi.com';\n\n // NB: v1 is legacy - v3 is the newest\n private const string ENDPOINT_PIPELINES = '/crm-pipelines/v1/pipelines/';\n private const string PIPELINE_OBJECT_TYPE_DEALS = 'deals';\n\n private const int TASK_VERIFICATION_CACHE_TTL = 86400; // 1 day\n\n /**\n * @var ClientInterface|Client\n */\n protected $client;\n protected OpportunitySyncStrategyResolver $opportunitySyncStrategyResolver;\n protected CrmEntityRepository $crmEntityRepository;\n protected ProspectPhotoPathService $prospectPhotoPathService;\n\n private SyncFieldAction $syncFieldAction;\n private PayloadBuilder $payloadBuilder;\n private SyncRelatedActivityManager $syncRelatedActivityManager;\n private SyncArchivedProfilesAction $syncArchivedProfilesAction;\n private WebhookSyncBatchProcessor $batchProcessor;\n\n public function __construct(\n Client $client,\n SyncFieldAction $syncFieldAction,\n PayloadBuilder $payloadBuilder,\n ProspectPhotoPathService $prospectPhotoPathService,\n SyncArchivedProfilesAction $syncArchivedProfilesAction,\n WebhookSyncBatchProcessor $batchProcessor,\n ) {\n parent::__construct();\n\n $this->client = $client;\n $this->syncFieldAction = $syncFieldAction;\n $this->prospectPhotoPathService = $prospectPhotoPathService;\n $this->payloadBuilder = $payloadBuilder;\n $this->syncArchivedProfilesAction = $syncArchivedProfilesAction;\n $this->batchProcessor = $batchProcessor;\n $this->opportunitySyncStrategyResolver = app(OpportunitySyncStrategyResolver::class, [\n 'client' => $this->client,\n ]);\n $this->syncRelatedActivityManager = app(SyncRelatedActivityManager::class, [\n 'client' => $this->client,\n 'payloadBuilder' => $this->payloadBuilder,\n 'logger' => $this->logger,\n ]);\n $this->crmEntityRepository = app(CrmEntityRepository::class);\n $this->dealFieldsService = app(DealFieldsService::class);\n }\n\n public function getDisplayName(): string\n {\n return 'HubSpot';\n }\n\n protected function getOAuthAccount(User $user): ?SocialAccount\n {\n // In this case, the Account Owner is always the connection for any API operations.\n $owner = $user->team->owner;\n\n return $owner->getSocialAccount(SocialAccount::PROVIDER_HUBSPOT);\n }\n\n public function getClient(): Client\n {\n /** @var Client */\n return $this->client;\n }\n\n /**\n * Convert raw field data into a format compatible with CRM APIs.\n *\n * @param bool $internal Direction of the conversion.\n * True is pulling from CRM, false normalize before sending to CRM.\n */\n public function normalizeValue(string $fieldType, string $fieldValue, bool $internal = false): string\n {\n return ValueNormalizer::normalize(\n fieldType: $fieldType,\n fieldValue: $fieldValue,\n isInbound: $internal,\n );\n }\n\n /**\n * @inheritdoc\n */\n public function getDefaultFields(string $activityType): array\n {\n $fields = [];\n\n if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {\n $defaultFields = FieldDefinitions::defaultTaskFields();\n\n // This lazy creates these fields if not already setup.\n foreach ($defaultFields as $defaultField) {\n $fields[] = $this->config->fields()->firstOrCreate($defaultField);\n }\n }\n\n return $fields;\n }\n\n /**\n * @inheritdoc\n */\n public function getDefaultActivityField(string $activityType): Field\n {\n /** @var Field $activityField */\n $activityField = $this->config->fields()->where([\n 'crm_provider_id' => 'activityType',\n 'object_type' => $activityType,\n ])->first();\n\n return $activityField;\n }\n\n /**\n * @inheritdoc\n */\n public function getSupportedPlaybookTypes(): array\n {\n return [Playbook::ACTIVITY_TYPE_TASK];\n }\n\n /**\n * @inheritdoc\n */\n public function getDefaultActivityLayoutFields(string $activityType, string $layoutType): array\n {\n $fields = [];\n\n if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {\n // Outcome should always be provided calls/meetings.\n $fieldData = [\n [\n 'crm_provider_id' => $layoutType === Layout::TYPE_SOFTPHONE_SUMMARY ? 'disposition' : 'meetingOutcome',\n 'object_type' => Field::OBJECT_TASK,\n ],\n ];\n\n foreach ($fieldData as $data) {\n $field = $this->config->fields()->where($data)->first();\n\n // Only add the field if it is created, which it should be.\n if ($field) {\n $fields[] = $field;\n }\n }\n }\n\n return $fields;\n }\n\n public function getDealInsightsFields(): array\n {\n return FieldDefinitions::dealInsightsFields();\n }\n\n protected function getDefaultFollowupLayoutFields(string $activityType): array\n {\n $fields = [];\n $fieldRepo = app(FieldRepository::class);\n $fieldData = FieldDefinitions::followupFieldsFilter();\n\n foreach ($fieldData as $data) {\n $field = $fieldRepo->findOneConfigurationFieldByProperties($this->config, $data);\n\n // Only add the field if it is created, which it should be.\n if ($field) {\n $fields[] = $field;\n }\n }\n\n return $fields;\n }\n\n /**\n * @inheritdoc\n */\n public function syncField(Field $field): void\n {\n switch ($field->object_type) {\n case Field::OBJECT_ACCOUNT:\n $crmField = $this->client->getInstance()->companyProperties()->get($field->crm_provider_id);\n\n break;\n case Field::OBJECT_CONTACT:\n $crmField = $this->client->getInstance()->contactProperties()->get($field->crm_provider_id);\n\n break;\n case Field::OBJECT_OPPORTUNITY:\n $crmField = $this->client->getInstance()->dealProperties()->get($field->crm_provider_id);\n\n break;\n case Field::OBJECT_TASK:\n $this->syncSingleTaskField($field);\n\n return;\n default:\n return;\n }\n\n $this->syncFieldAction->execute($field, $crmField->toArray());\n }\n\n /**\n * @param array<array{\n * id:string,\n * label:string,\n * value?:string\n * }> $options\n *\n * @throws CrmException\n *\n * @return FieldData[]\n *\n */\n public function importPicklistValues(\n Field $field,\n array $options = [['id' => '', 'label' => '', 'value' => '']],\n ): array {\n if (! empty($options[0]['id']) || ! empty($options[0]['value'])) {\n // We already have the options, no need to fetch them again\n return $this->importOptions($field, $options);\n }\n\n $options = [];\n\n switch ($field->getObjectType()) {\n case Field::OBJECT_ACCOUNT:\n $options = $this->getClient()->fetchPropertyOptions('company', $field->getCrmProviderId());\n\n break;\n\n case Field::OBJECT_CONTACT:\n $options = $this->getClient()->fetchPropertyOptions('contact', $field->getCrmProviderId());\n\n break;\n\n case Field::OBJECT_OPPORTUNITY:\n // Hubspot has different endpoint for stages\n $options = $this->getClient()->fetchOpportunityFieldOptions($field);\n\n break;\n\n case Field::OBJECT_TASK:\n if ($field->getCrmProviderId() === 'disposition') {\n $options = $this->getClient()->fetchDispositionFieldOptions();\n } elseif (in_array($field->getCrmProviderId(), ['meetingOutcome', 'activityType'])) {\n $options = $this->getClient()->fetchMeetingOutcomeFieldOptions($field);\n }\n\n break;\n\n default:\n $this->logger->warning('Invalid object type', [\n 'object_type' => $field->getObjectType(),\n 'field_id' => $field->getId(),\n ]);\n\n throw new CrmException('Invalid object type');\n }\n\n return $this->importOptions($field, $options);\n }\n\n /**\n * @inheritdoc\n */\n public function importStages(?array $types = null, ?string $missingStageName = null): ?Stage\n {\n $missingStage = null;\n\n try {\n // Use the HubSpot API client instead of the SDK crmPipelines() method\n $endpoint = self::getDealsPipelinesEndpoint();\n $pipelinesResponse = $this->client->getInstance()->getClient()->request('GET', $endpoint);\n $pipelines = $pipelinesResponse->data->results;\n } catch (RequestException|BadRequest $exception) {\n throw $exception;\n }\n\n foreach ($pipelines as $pipeline) {\n $stages = [];\n\n // We create a business process to contain the pipeline, and store all stages against it.\n $p = ResponseNormalize::normalizePipeline($pipeline);\n\n // Create/update business process for this pipeline\n $businessProcess = $this->config->businessProcesses()->updateOrCreate([\n 'crm_provider_id' => $p['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($p['label'], 0, 150),\n 'type' => BusinessProcess::TYPE_OPPORTUNITY,\n 'is_selectable' => $p['active'],\n ]);\n\n // A record type is really a clone of the business process, used to store which record uses which pipeline.\n // Create/update record type clone\n $this->config->recordTypes()->updateOrCreate([\n 'crm_provider_id' => $p['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($p['label'], 0, 150),\n 'is_selectable' => $p['active'],\n 'business_process_id' => $businessProcess->id ?? null,\n ]);\n\n // Stages - fetch all existing stages upfront to avoid N+1 queries\n $existingStages = $this->config->stages()\n ->withTrashed()\n ->where('type', Stage::TYPE_OPPORTUNITY)\n ->get()\n ->keyBy('crm_provider_id');\n\n foreach ($p['stages'] as $dealStage) {\n $s = ResponseNormalize::normalizeDealStage($dealStage);\n\n /** @var ?Stage $existingStage */\n $existingStage = $existingStages->get($s['id']);\n\n // Restore soft-deleted stages that are now active in HubSpot\n if ($existingStage?->trashed() && $s['active']) {\n $existingStage->restore();\n }\n\n // Upsert stage (updates soft-deleted records without restoring them)\n $stage = $this->config->stages()->withTrashed()->updateOrCreate([\n 'crm_provider_id' => $s['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($s['label'], 0, 50),\n 'label' => mb_strimwidth($s['label'], 0, 191),\n 'type' => Stage::TYPE_OPPORTUNITY,\n 'sequence' => $s['displayOrder'],\n 'is_selectable' => $s['active'],\n 'probability' => $s['probability'] * 100,\n ]);\n\n if ($missingStageName === $s['id']) {\n $missingStage = $stage;\n }\n\n $stages[] = $stage->id;\n }\n\n $businessProcess->stages()->sync($stages);\n }\n\n return $missingStage;\n }\n\n /**\n * @inheritdoc\n */\n public function syncOrganization(): void\n {\n try {\n $endpoint = 'https://api.hubapi.com/integrations/v1/me';\n $response = $this->client->getInstance()->getClient()->request('get', $endpoint);\n\n $accountData = $response->data;\n $this->config->update(['default_currency' => $accountData->currency]);\n } catch (BadRequest $e) {\n throw new CrmException('Could not sync the organization.', $e->getCode(), $e);\n }\n }\n\n /**\n * @inheritdoc\n *\n * @throws CrmException\n */\n public function syncProfiles(?User $userToSearch = null): ?Profile\n {\n $this->syncArchivedProfilesAction->execute($this->team, $this->client, $this->config);\n\n try {\n $owners = $this->client->getOwners();\n } catch (\\HubSpot\\Client\\Crm\\Owners\\ApiException $e) {\n $this->logger->error('[HubSpot] Could not sync the profiles.', [\n 'team_id' => $this->team->getId(),\n 'reason' => $e->getMessage(),\n ]);\n\n throw new CrmException('Could not sync the profiles.', $e->getCode(), $e);\n }\n\n $profileRepository = app(ProfileRepository::class);\n $teamRepository = app(TeamRepository::class);\n\n foreach ($owners as $owner) {\n if ($owner->getArchived()) {\n // not supposed to fetch archived, but log anyway\n $this->logger->warning('[HubSpot] Found archived owner', [\n 'crm_provider_id' => $owner->getId(),\n 'email' => $owner->getEmail(),\n ]);\n\n continue;\n }\n\n $email = $owner->getEmail();\n if ($email === null) {\n continue;\n }\n\n $user = $teamRepository->findActiveTeamMemberByEmail($this->team, $email);\n\n if (! $user instanceof User) {\n continue;\n }\n\n $profile = $profileRepository->updateOrCreateProfile($user, [\n 'crm_configuration_id' => $this->config->getId(),\n 'crm_provider_id' => $owner->getId(),\n ]);\n\n if ($userToSearch && $userToSearch->getId() === $user->getId()) {\n return $profile;\n }\n }\n\n return null;\n }\n\n private function generateNameSearchPayload(string $name, int $offset, int $limit): array\n {\n $payload = [\n 'query' => $name,\n 'sorts' => [\n [\n 'propertyName' => 'modifieddate',\n 'direction' => 'DESCENDING',\n ],\n ],\n 'properties' => [\n 'email',\n 'firstname',\n 'lastname',\n 'country',\n 'phone',\n 'mobilephone',\n 'jobtitle',\n 'hubspot_owner_id',\n 'associatedcompanyid',\n 'photo',\n 'industry',\n 'name',\n 'company',\n ],\n 'limit' => $limit,\n 'after' => $offset,\n ];\n\n $this->logger->debug('[HubSpot] CRM Search requested', [\n 'request' => $payload,\n ]);\n\n return $payload;\n }\n\n /**\n * @inheritdoc\n */\n public function find(string $name, array $scopes): array\n {\n $count = $this->limit ?? 20;\n $offset = $this->offset ?? 0;\n\n /** @var array<int, array<string, mixed>> */\n return Cache::remember(\n key: $this->team->getId() . $name . $count . $offset,\n ttl: 300,\n callback: function () use ($name, $offset, $count): array {\n $data = [];\n\n // Use the new V3 API to find contacts based on additional fields.\n foreach (['companies', 'contacts'] as $objectType) {\n $endpoint = 'https://api.hubapi.com/crm/v3/objects/' . $objectType . '/search';\n $payload = $this->generateNameSearchPayload($name, $offset, $count);\n $type = $objectType === 'companies' ? 'account' : 'contact';\n\n try {\n $response = $this->client->getInstance()->getClient()->request('POST', $endpoint, [\n 'json' => $payload,\n ]);\n\n // Build mapped list.\n foreach ($response['results'] as $object) {\n $properties = $object['properties'];\n\n $objectName = $this->buildContactName($properties);\n\n $record = [\n 'crmId' => $object['id'],\n // Pass crmUrl to the FE, needed for success message in the extension when you log activity.\n 'crmUrl' => $this->generateProviderUrl($object['id'], $type),\n 'name' => $objectName,\n 'prospectType' => $type,\n 'phoneNumbers' => [],\n ];\n\n if ($type === 'account') {\n $record['industry'] = $properties['industry'] ?? null;\n } else {\n $record['title'] = $properties['jobtitle'] ?? null;\n $record['organization'] = $properties['company'] ?? null;\n }\n\n $countryCode = $this->buildContactCountry($properties);\n $parsedNumber = $this->buildContactPhone($countryCode, $properties);\n\n // Add phone number to record.\n if (! empty($parsedNumber['phone'])) {\n $record['phoneNumbers'][] = [\n 'number' => $parsedNumber['phone'],\n 'nationalFormat' => phone_national($countryCode, $parsedNumber['phone']),\n 'type' => 'phone',\n ];\n }\n\n // Add mobile phone number to record.\n if (! empty($properties['mobilephone'])) {\n $mobileNumber = phone_e164($countryCode, $properties['mobilephone']);\n if ($mobileNumber !== null) {\n $record['phoneNumbers'][] = [\n 'number' => $mobileNumber,\n 'nationalFormat' => phone_national($countryCode, $mobileNumber),\n 'type' => 'mobile',\n ];\n }\n }\n\n $data[] = $record;\n }\n } catch (BadRequest $e) {\n $this->logger->warning('[' . $this->getDisplayName() . '] Search failed', [\n 'teamId' => $this->team->getUuid(),\n 'request' => $payload,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n }\n\n return $data;\n },\n );\n }\n\n\n /**\n * @inheritdoc\n */\n public function findOpportunities(?string $crmAccountId, ?string $crmContactId, ?int $userId = null): array\n {\n $data = [];\n $ownerData = [];\n $ownerId = null;\n\n if ($crmAccountId === null) {\n return $data;\n }\n\n if ($userId) {\n $profileRepository = app(ProfileRepository::class);\n $profile = $profileRepository->findProfileByUserId($this->config, $userId);\n\n $ownerId = $profile instanceof Profile ? $profile->getCrmProviderId() : null;\n }\n\n $closedStages = $this->getClosedDealStages();\n $payload = $this->payloadBuilder->generateOpportunitiesSearchPayload(\n $this->config,\n $crmAccountId,\n $closedStages,\n );\n\n $results = $this->client->getPaginatedData($payload, 'deals');\n\n foreach ($results['results'] as $object) {\n $properties = $object['properties'];\n\n $amount = null;\n if (empty($properties['amount']) === false) {\n $currency = $properties['deal_currency_code'] ?? $this->config->default_currency;\n\n // Values can contain commas and any junk so strip them.\n $value = (float) preg_replace('/[^\\d.]/', '', $properties['amount']);\n $amount = formatCurrency($value, $currency);\n }\n\n $businessProcess = $this->config\n ->businessProcesses()\n ->where('crm_provider_id', $properties['pipeline'])\n ->first();\n\n if ($businessProcess === null) {\n // Import it.\n $stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $properties['dealstage']);\n $businessProcess = $this->config\n ->businessProcesses()\n ->where('crm_provider_id', $properties['pipeline'])\n ->first();\n } else {\n $stage = $businessProcess\n ->stages()\n ->where('crm_provider_id', $properties['dealstage'])\n ->where('type', Stage::TYPE_OPPORTUNITY)\n ->first();\n\n if ($stage === null) {\n // Import it.\n $stage = $this->importStages(null, $properties['dealstage']);\n }\n }\n\n $recordType = null;\n if ($businessProcess) {\n $recordType = $businessProcess->recordTypes()->first();\n }\n\n $isWon = in_array($properties['dealstage'], $closedStages['won']);\n $isLost = in_array($properties['dealstage'], $closedStages['lost']);\n\n $record = [\n 'crmId' => $object['id'],\n 'name' => $properties['dealname'] ?? 'Unknown Deal',\n 'value' => $amount,\n 'won' => $isWon,\n 'closed' => $isWon || $isLost,\n 'stage' => [\n 'id' => $stage?->getUuid() ?? '',\n 'name' => $stage?->getName() ?? '',\n ],\n ];\n\n if ($recordType) {\n $record += [\n 'recordType' => [\n 'id' => $recordType->id_string,\n 'name' => $recordType->name,\n ],\n ];\n }\n\n if ($ownerId && isset($properties['hubspot_owner_id']) && $properties['hubspot_owner_id'] === $ownerId) {\n $ownerData[] = $record;\n }\n\n $data[] = $record;\n }\n\n if (! empty($ownerData)) {\n return $ownerData;\n }\n\n return $data;\n }\n\n /**\n * @inheritdoc\n */\n public function getTasks(?string $objectType, string $objectId, ?string $opportunityId): array\n {\n $data = [];\n switch ($objectType) {\n case 'contact':\n $hsObject = 'contact';\n\n break;\n case 'account':\n $hsObject = 'company';\n\n break;\n default:\n // This is a hack to prioritise and override a contact/company with a deal.\n if ($opportunityId) {\n $hsObject = 'deal';\n $objectId = $opportunityId;\n } else {\n throw new InvalidArgumentException('Object type not supported.');\n }\n }\n\n $engagementTypes = ['meetings', 'tasks'];\n\n foreach ($engagementTypes as $engagementType) {\n $payload = $this->payloadBuilder->getLinkToTaskPayload($hsObject, $objectId, $engagementType);\n\n $this->logger->info('[HubSpot] CRM Search requested', [\n 'request' => $payload,\n ]);\n\n $engagements = $this->client->getPaginatedData($payload, $engagementType);\n\n foreach ($engagements['results'] as $engagement) {\n if ($engagementType == 'meetings') {\n $title = $engagement['properties']['hs_meeting_title'] ?? 'Scheduled meeting';\n } elseif ($engagementType == 'tasks') {\n $title = $engagement['properties']['hs_task_subject'];\n } else {\n $title = 'Scheduled meeting';\n }\n\n $data[] = [\n 'crmId' => $engagement['id'],\n 'subject' => $title,\n 'due' => $engagement['properties']['hs_timestamp'],\n 'type' => $engagement['properties']['hs_activity_type'] ?? null,\n ];\n }\n }\n\n usort($data, function ($item1, $item2) {\n return $item2['due'] <=> $item1['due'];\n });\n\n return $data;\n }\n\n /**\n * Try to find CRM Objects using email address\n *\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n * }\n */\n public function matchExactlyByEmail(string $email, ?int $userId = null): ?array\n {\n $contactProperties = [\n 'email',\n 'firstname',\n 'lastname',\n 'country',\n 'phone',\n 'mobilephone',\n 'jobtitle',\n 'hubspot_owner_id',\n 'associatedcompanyid',\n 'photo',\n ];\n $contact = null;\n $account = null;\n\n try {\n $hsContact = $this->getClient()->getContactByEmail($email, $contactProperties);\n\n if ($hsContact) {\n $contact = $this->importContact($hsContact);\n $account = $contact->account;\n }\n\n $data = $this->convertCrmData($contact, $account, $userId);\n\n return ! empty(array_filter($data)) ? $data : null;\n } catch (BadRequest $e) {\n $this->logger->warning('[HubSpot] Search failed', [\n 'team_id' => $this->team->getId(),\n 'search_identifier' => $email,\n 'reason' => $e->getMessage(),\n ]);\n }\n\n return null;\n }\n\n public function getDomain(string $email): ?string\n {\n return $this->getDomainFromEmail($email);\n }\n\n /**\n * Try to find CRM objects using domain name of the email address\n *\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n * }\n */\n public function matchByDomain(string $domain, ?int $userId = null): ?array\n {\n $companyName = $domain;\n\n // Try to find a company matching their email domain.\n $companyProperties = [\n 'country',\n 'phone',\n 'name',\n 'hs_avatar_filemanager_key',\n 'industry',\n 'hubspot_owner_id',\n 'domain',\n ];\n\n try {\n $hsAccounts = $this->client\n ->getInstance()\n ->companies()\n ->searchByDomain($companyName, $companyProperties);\n } catch (Throwable $e) {\n $this->logger->info('[HubSpot] Search failed', [\n 'error' => $e->getMessage(),\n 'domain' => $domain,\n ]);\n\n return null;\n }\n\n $account = null;\n // If there are multiple accounts, don't guess, we'll ask later.\n if (\\count($hsAccounts->data->results) === 1) {\n // Persist this remote object.\n $account = $this->syncAccount($hsAccounts->data->results[0]->companyId);\n }\n\n $data = $this->convertCrmData(null, $account, $userId);\n\n return ! empty(array_filter($data)) ? $data : null;\n }\n\n /**\n * @return array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n * }\n */\n protected function convertCrmData(?Contact $contact, ?Account $account, ?int $userId = null): array\n {\n $countryCode = null;\n if ($contact && $contact->country_code) {\n $countryCode = $contact->country_code;\n } elseif ($account && $account->country_code) {\n $countryCode = $account->country_code;\n }\n\n try {\n $hsOpportunities = $this->findOpportunities(\n $account ? $account->crm_provider_id : null,\n $contact ? $contact->crm_provider_id : null,\n $userId\n );\n } catch (Exception $e) {\n $hsOpportunities = [];\n }\n\n // If there are multiple opportunities, don't guess, we'll ask later.\n $opportunity = null;\n $stage = null;\n if (! empty($hsOpportunities)) {\n // Persist this remote object.\n $opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);\n $stage = $opportunity?->getStage();\n }\n\n return [\n null,\n $account,\n $opportunity,\n $contact,\n $stage,\n $countryCode,\n ];\n }\n\n protected function getCacheKey(string $object, ?int $userId = null): ?string\n {\n $key = $this->team->getId() . $object;\n $keySuffix = $this->getOwnerKeySuffix($userId);\n\n return $key . $keySuffix;\n }\n\n private function getOwnerKeySuffix(?int $userId = null): string\n {\n return $userId === null ? '' : (string) $userId;\n }\n\n /**\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n *}\n */\n public function matchByPhone(string $phone, ?string $rawPhoneNumber = null, ?int $userId = null): ?array\n {\n if (str_contains($phone, '**')) {\n return null;\n }\n\n // trim all whitespaces if present so the lookup doesn't fail\n $phone = str_replace(' ', '', $phone);\n\n // Check if the user is internal.\n if ($this->isPhoneNumberOfTeamMember($phone)) {\n return null;\n }\n\n $response = $this->searchForPhoneNumber($phone);\n if (empty($response)) {\n return null;\n }\n\n // This would ideally importContact instead but the response type differs.\n $contact = $this->findAndSyncContact($response['results'][0]['id']);\n if (! $contact instanceof Contact) {\n return null;\n }\n\n $account = $contact->account;\n $countryCode = $contact->country_code ?? $account->country_code ?? null;\n\n try {\n $hsOpportunities = $this->findOpportunities(\n $account?->crm_provider_id,\n $contact->crm_provider_id,\n $userId\n );\n } catch (Exception $e) {\n $hsOpportunities = [];\n }\n\n $opportunity = null;\n $stage = null;\n\n try {\n if (! empty($hsOpportunities)) {\n // Persist this remote object.\n $opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);\n $stage = $opportunity?->getStage();\n }\n } catch (Exception $e) {\n $this->logger->debug('[HubSpot] Opportunity failed to sync.', [\n 'reason' => $e->getMessage(),\n ]);\n }\n\n return [\n null,\n $account,\n $opportunity,\n $contact,\n $stage,\n $countryCode,\n ];\n }\n\n private function isPhoneNumberOfTeamMember(string $phone): bool\n {\n $teamRepository = app(TeamRepository::class);\n $user = $teamRepository->findTeamMemberByPhone($this->team, $phone);\n\n if ($user instanceof User) {\n return true;\n }\n\n return false;\n }\n\n private function findAndSyncContact(string $crmId): ?Contact\n {\n try {\n return $this->syncContact($crmId);\n } catch (Exception $exception) {\n $this->logger->info('[HubSpot] Phone match failed', [\n 'reason' => $exception->getMessage(),\n ]);\n\n return null;\n }\n }\n\n private function hasResults(array $response): bool\n {\n return isset($response['total']) && is_numeric($response['total']) && $response['total'] > 0;\n }\n\n private function searchForPhoneNumber(string $phone): array\n {\n // Normalizes the provided phone number for the API search.\n $normalizedPhone = $this->normalizePhoneNumber($phone);\n $payload = $this->payloadBuilder->generatePhoneSearchPayload($normalizedPhone);\n\n $this->logger->info('[HubSpot] Phone match search triggered', [\n 'phone' => $phone,\n 'normalizedPhone' => $normalizedPhone,\n 'payload' => $payload,\n ]);\n\n $response = $this->handlePhoneSearchRequest($normalizedPhone, $payload);\n\n if (! $this->hasResults($response)) {\n $nationalPhone = preg_replace('/\\D/', '', phone_national(null, $phone));\n $payload = $this->payloadBuilder->generatePhoneSearchPayload($nationalPhone);\n\n $this->logger->info('[HubSpot] Phone match national number search triggered', [\n 'phone' => $phone,\n 'nationalPhone' => $nationalPhone,\n 'payload' => $payload,\n ]);\n\n $response = $this->handlePhoneSearchRequest($phone, $payload);\n }\n\n if (! $this->hasResults($response)) {\n $payload = $this->payloadBuilder->generatePhoneSearchPayload($normalizedPhone, true);\n\n $this->logger->info('[HubSpot] Phone match alternative search triggered', [\n 'phone' => $phone,\n 'normalizedPhone' => $normalizedPhone,\n 'payload' => $payload,\n ]);\n\n $response = $this->handlePhoneSearchRequest($phone, $payload);\n }\n\n return $this->hasResults($response) ? $response : [];\n }\n\n private function handlePhoneSearchRequest(string $phone, array $payload): array\n {\n $endpoint = 'https://api.hubapi.com/crm/v3/objects/contacts/search';\n\n try {\n $response = $this->client->getInstance()->getClient()->request(\n 'POST',\n $endpoint,\n ['json' => ($payload)],\n );\n } catch (Exception $exception) {\n $this->logger->info('[HubSpot] Phone match failed', [\n 'phone' => $phone,\n 'reason' => $exception->getMessage(),\n ]);\n\n return [];\n }\n\n $this->logger->info('[HubSpot] Phone match completed', [\n 'phone' => $phone,\n 'response' => $response,\n ]);\n\n return $response->toArray();\n }\n\n private function normalizePhoneNumber(string $phone): string\n {\n return ltrim(phone_e164(null, $phone), '+0');\n }\n\n /**\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n * }\n */\n public function matchByName(string $name, ?int $userId = null): ?array\n {\n // Don't waste time searching for single character strings.\n if (\\strlen($name) <= 1) {\n return null;\n }\n\n $cacheKey = $this->getCacheKey($name, $userId);\n\n $result = Cache::remember($cacheKey, 60, function () use ($name, $userId) {\n $payload = $this->payloadBuilder->generateSearchContactsByNamePayload(\n $name,\n $this->getContactFields()\n );\n\n $hsContacts = $this->client->getPaginatedData($payload, 'contact');\n if (empty($hsContacts['results'])) {\n return false;\n }\n\n $contact = $this->importContact($hsContacts['results'][0]);\n if ($contact === null) {\n return false;\n }\n\n $account = $contact->account;\n $countryCode = $contact->country_code ?? $account->country_code ?? null;\n\n try {\n $hsOpportunities = $this->findOpportunities(\n $account ? $account->crm_provider_id : null,\n $contact->crm_provider_id,\n $userId\n );\n } catch (Exception $e) {\n $hsOpportunities = [];\n }\n\n $opportunity = null;\n $stage = null;\n if (! empty($hsOpportunities)) {\n // Persist this remote object.\n $opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);\n $stage = $opportunity?->getStage();\n }\n\n return [\n null,\n $account,\n $opportunity,\n $contact,\n $stage,\n $countryCode,\n ];\n });\n\n return is_array($result) ? $result : null;\n }\n\n\n private function convertActivityAssociations(Activity $activity): array\n {\n return [\n 'contactIds' => $this->getParticipantsIds($activity),\n 'companyIds' => $activity->hasAccount() ? [$activity->account->crm_provider_id] : [],\n 'dealIds' => $activity->hasOpportunity() ? [$activity->opportunity->crm_provider_id] : [],\n 'ownerIds' => [],\n ];\n }\n\n private function getParticipantsIds(Activity $activity): array\n {\n $attendees = [];\n\n $participantRepository = app(ParticipantRepository::class);\n $participants = $participantRepository->getParticipantsWhoEnteredMeeting($activity);\n foreach ($participants as $participant) {\n if ($participant->user_id || $participant->isCoach()) {\n continue;\n }\n\n $contact = $participant->contact()->first();\n if ($contact && $contact->crm_provider_id) {\n $attendees[] = $contact->crm_provider_id;\n } else {\n if (! empty($participant->name)) {\n $attendeeData = $this->fetchMissingAttendeeInfo($participant);\n }\n if (! empty($attendeeData['id'])) {\n $attendees[] = $attendeeData['id'];\n }\n }\n }\n\n if ($activity->hasContact()) {\n $attendees[] = $activity->contact->crm_provider_id;\n }\n\n return array_unique($attendees);\n }\n\n private function fetchMissingAttendeeInfo(Participant $participant): array\n {\n // Check if we need to look inside an account context.\n $activity = $participant->getActivity();\n $companyId = $activity->hasAccount() ? $activity->getAccount()->crm_provider_id : null;\n\n // First check the local data.\n /** @var Contact[] $contacts */\n $contacts = $this->team->contacts()\n ->with('account')\n ->where('name', $participant->name)\n ->whereNotNull('email')\n ->get();\n\n foreach ($contacts as $contact) {\n // If we have a company in scope, check the contact is associated to it.\n if (\n $companyId !== null\n && ($contact->account_id === null || $companyId !== $contact->account->crm_provider_id)\n ) {\n continue;\n }\n\n return [\n 'id' => $contact->crm_provider_id,\n 'email' => $contact->email,\n ];\n }\n\n $payload = $this->generateNameSearchPayload($participant->name, 0, 20);\n\n try {\n $response = $this->client->getNewInstance()->crm()->contacts()->searchApi()->doSearch($payload);\n\n // TODO add some logic to choose the most suitable contact if multiple\n foreach ($response['results'] as $object) {\n $properties = $object['properties'];\n if (empty($object['properties']) === false) {\n // Check the company matches the contact.\n // Todo: Move this check inside the API search.\n if ($companyId !== null && $companyId !== $properties['associatedcompanyid']) {\n continue;\n }\n\n return [\n 'id' => $object['id'],\n 'email' => $properties['email'],\n ];\n }\n }\n } catch (Exception $e) {\n $this->logger->warning('[' . $this->getDisplayName() . '] Search failed', [\n 'teamId' => $this->team->id_string,\n 'request' => $payload,\n 'reason' => $e->getMessage(),\n ]);\n }\n\n return [];\n }\n\n /**\n * Store transcripts as note engagement.\n *\n * @throws Exception\n */\n public function createTranscriptNotes(Activity $activity): void\n {\n // For HS no need to check if Crm profile - Log Notes field is enabled\n // We only check if store_transcript toggle is enabled on crm profile.\n $engagement = [\n 'active' => true,\n 'ownerId' => $this->profile->crm_provider_id,\n 'timestamp' => $activity->created_at->tz($activity->user->timezone)->getTimestamp() * 1000,\n 'type' => 'NOTE',\n ];\n\n // Generate activity transcription.\n $transcriptionData = $this->generateTranscription($activity);\n\n // Truncate Notes with max notes length because transcription text could be very long.\n $transcripts = mb_strimwidth($transcriptionData, 0, static::ENGAGEMENT_BODY_MAX_LENGTH);\n\n $metadata = [\n 'body' => $transcripts,\n ];\n\n $associations = $this->convertActivityAssociations($activity);\n\n try {\n $hsEngagement = $this->client\n ->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n\n $this->logCrmEngagementManipulation(self::ACTION_CREATE, $engagement, $metadata, $associations);\n\n $noteId = $hsEngagement->data->engagement->id;\n\n // Store crm logged id in transcription.\n $transcription = $activity->getTranscription();\n $transcription->crm_activity_id = $noteId;\n $transcription->save();\n } catch (Exception $e) {\n Sentry::captureException($e);\n }\n }\n\n /*\n * @inheritdoc\n */\n public function updateRecord(string $objectType, string $objectId, array $data, array $headers = []): void\n {\n $payload = [\n 'properties' => $data,\n ];\n\n try {\n switch ($objectType) {\n case FieldData::OBJECT_OPPORTUNITY:\n $this->client->getNewInstance()->crm()->deals()->basicApi()->update($objectId, $payload);\n\n break;\n case FieldData::OBJECT_CONTACT:\n $this->client->getNewInstance()->crm()->contacts()->basicApi()->update($objectId, $payload);\n\n break;\n\n case FieldData::OBJECT_ACCOUNT:\n $this->client->getNewInstance()->crm()->companies()->basicApi()->update($objectId, $payload);\n\n break;\n\n case FieldData::OBJECT_TASK:\n // Endpoint for Engagements not ready\n $engagements = [\n 'type' => 'TASK',\n ];\n $metadata = $data;\n $this->client->getInstance()->engagements()->update($objectId, $engagements, $metadata);\n\n $this->logCrmEngagementManipulation(\n self::ACTION_UPDATE,\n ['crmId' => $objectId],\n $metadata,\n );\n\n break;\n\n default:\n throw new UnexpectedValueException('Unsupported object type \"' . $objectType . '\"');\n }\n } catch (\\HubSpot\\Client\\Crm\\Deals\\ApiException $apiException) {\n $errorMessage = $apiException->getMessage();\n if ($apiException->getResponseBody()) {\n $responseBody = json_decode($apiException->getResponseBody(), true, 512, JSON_THROW_ON_ERROR);\n $errorMessage = $responseBody['message'] ?? $apiException->getMessage();\n }\n\n $this->logger->error(\n '[HubSpot] Update record failed',\n [\n 'objectType' => $objectType,\n 'objectId' => $objectId,\n 'payload' => $payload,\n 'reason' => $errorMessage,\n 'team' => $this->team->getUuid(),\n ]\n );\n\n throw new CrmException($errorMessage);\n }\n }\n\n /*\n * @inheritdoc\n */\n public function getRecord(string $objectType, string $objectId, array $fields = []): array\n {\n switch ($objectType) {\n case FieldData::OBJECT_OPPORTUNITY:\n return $this->client->getInstance()->deals()->getById($objectId)->toArray();\n\n case FieldData::OBJECT_CONTACT:\n return $this->client->getInstance()->contacts()->getById($objectId)->toArray();\n\n case FieldData::OBJECT_ACCOUNT:\n return $this->client->getInstance()->companies()->getById($objectId)->toArray();\n\n case FieldData::OBJECT_TASK:\n return $this->client->getInstance()->engagements()->get($objectId)->toArray();\n\n default:\n throw new UnexpectedValueException('Unsupported object type \"' . $objectType . '\"');\n }\n }\n\n /**\n * @throws BadRequest\n * @throws CrmException\n */\n public function updateStage($crmObject, Stage $stage): void\n {\n $payload = [\n 'properties' => [\n [\n 'name' => 'dealstage',\n 'value' => $stage->crm_provider_id,\n ],\n ],\n ];\n\n try {\n $this->client->getInstance()->deals()->update($crmObject->crm_provider_id, $payload);\n } catch (BadRequest $badRequest) {\n if ($badRequest->getCode() === 403) {\n throw new CrmException(\n \"Sorry, you don't have permission to update this stage.\",\n $badRequest->getCode(),\n $badRequest,\n );\n }\n\n $this->logger->warning('[HubSpot] Stage update failed', [\n 'dealId' => $crmObject->crm_provider_id,\n 'payload' => $payload,\n 'message' => $badRequest->getMessage(),\n ]);\n\n throw $badRequest;\n }\n }\n\n public function generateProviderUrl(string $providerId, string $objectType): ?string\n {\n $url = null;\n $baseUrl = 'https://app.hubspot.com/contacts/' . $this->config->crm_provider_id . '/';\n\n switch ($objectType) {\n case 'account':\n $url = $baseUrl . 'company/' . $providerId;\n\n break;\n\n case 'contact':\n $url = $baseUrl . 'contact/' . $providerId;\n\n break;\n\n case 'opportunity':\n $url = $baseUrl . 'deal/' . $providerId;\n\n break;\n\n case 'task':\n case 'activity':\n return null;\n\n // This should not be deep-linked as per JMNY-3934.\n //$url = $baseUrl.'tasks/list/view/all/?taskId='.$providerId;\n break;\n }\n\n return $url;\n }\n\n public function searchCalls(Carbon $from, Carbon $to, string $activityProvider): array\n {\n $this->logger->info('[HubSpot] Search calls', [\n 'from' => $from->format(self::LOG_DATE_FORMAT),\n 'to' => $to->format(self::LOG_DATE_FORMAT),\n ]);\n\n $calls = [];\n $page = 1;\n\n do {\n try {\n $payload = $this->payloadBuilder->generateGetCallsPayload($from, $to, $activityProvider, $page);\n $response = $this->client->getInstance()->getClient()->request(\n 'POST',\n self::CALLS_SEARCH_ENDPOINT,\n ['json' => ($payload)],\n );\n } catch (Exception $exception) {\n $this->logger->info('[HubSpot] Search calls failed', [\n 'from' => $from->format(self::LOG_DATE_FORMAT),\n 'to' => $to->format(self::LOG_DATE_FORMAT),\n 'reason' => $exception->getMessage(),\n ]);\n $response = null;\n }\n\n $responseResults = empty($response['results']) ? [] : $response['results'];\n $calls = array_merge($calls, $responseResults);\n $page++;\n } while (! empty($responseResults));\n\n return $calls;\n }\n\n public function searchCallsForPeriodByPage(Carbon $from, Carbon $to, int $page, bool $retry = true)\n {\n try {\n $payload = $this->payloadBuilder->generateSearchCallsByPeriodPayload($from, $to, $page);\n $response = $this->client->getInstance()->getClient()->request(\n 'POST',\n self::CALLS_SEARCH_ENDPOINT,\n ['json' => ($payload)],\n );\n } catch (Exception $exception) {\n $this->logger->info('[HubSpot] Search calls for period failed', [\n 'from' => $from->format(self::LOG_DATE_FORMAT),\n 'to' => $to->format(self::LOG_DATE_FORMAT),\n 'reason' => $exception->getMessage(),\n 'retry' => $retry,\n ]);\n\n if ($retry) {\n sleep(1);\n\n return $this->searchCallsForPeriodByPage($from, $to, $page, false);\n }\n $response = null;\n }\n\n return $response;\n }\n\n public function searchCallsForPeriod(Carbon $from, Carbon $to): Generator\n {\n $this->logger->info('[HubSpot] Search calls for period', [\n 'from' => $from->format(self::LOG_DATE_FORMAT),\n 'to' => $to->format(self::LOG_DATE_FORMAT),\n ]);\n\n $page = 1;\n\n do {\n $response = $this->searchCallsForPeriodByPage($from, $to, $page);\n\n $responseResults = empty($response['results']) ? [] : $response['results'];\n\n $associationContacts = $this->getAssociationDataForCollection($responseResults, 'calls', 'contacts');\n $associationCompanies = $this->getAssociationDataForCollection($responseResults, 'calls', 'companies');\n $associationDeals = $this->getAssociationDataForCollection($responseResults, 'calls', 'deals');\n\n foreach ($responseResults as $call) {\n $call['associations'] = [\n 'contacts' => $this->importAssociationData($call, $associationContacts),\n 'companies' => $this->importAssociationData($call, $associationCompanies),\n 'deals' => $this->importAssociationData($call, $associationDeals),\n ];\n\n yield $call;\n }\n $page++;\n } while (! empty($responseResults));\n }\n\n public function getCall(string $callId): array\n {\n $this->logger->info('[HubSpot] Get call', [\n 'call_id' => $callId,\n ]);\n\n $searchAttributes = $this->payloadBuilder->getSearchCallAttributes();\n $endpoint = sprintf(\n 'https://api.hubapi.com/crm/v3/objects/calls/%s',\n $callId,\n );\n\n try {\n $response = $this->client->getInstance()->getClient()->request(\n 'GET',\n $endpoint,\n [],\n sprintf(\n 'properties=%s&associations=contacts,companies,deals',\n implode(',', $searchAttributes),\n ),\n );\n } catch (Exception $exception) {\n $this->logger->info('[HubSpot] Get call failed', [\n 'call_id' => $callId,\n 'reason' => $exception->getMessage(),\n ]);\n $response = null;\n }\n\n return empty($response) ? [] : $response->toArray();\n }\n\n public function bulkAddPlaybackURLToDescription(array $crmUpdateData): array\n {\n $crmUpdateBatches = array_chunk($crmUpdateData, self::BATCH_UPDATE_LIMIT);\n\n $updatedCrmIds = [];\n\n foreach ($crmUpdateBatches as $crmBatch) {\n $payload = $this->payloadBuilder->generatePlaybackAddUrlBatchPayload($crmBatch);\n $updateSuccess = $this->bulkAddPlaybackURLToDescriptionRequest($payload);\n if ($updateSuccess) {\n $updatedCrmIds = array_merge($updatedCrmIds, array_column($crmBatch, 'crm_id'));\n }\n }\n\n return $updatedCrmIds;\n }\n\n private function bulkAddPlaybackURLToDescriptionRequest(array $payload, bool $retry = true): bool\n {\n try {\n $this->client->getNewInstance()->crm()->objects()->batchApi()->update('calls', $payload);\n\n return true;\n } catch (\\HubSpot\\Client\\Crm\\Objects\\ApiException $e) {\n $response = json_decode($e->getResponseBody(), true);\n $retryAfter =\n isset($response['policyName'])\n && $response['policyName'] == self::TEN_SECONDLY_ROLLING_POLICY\n ? self::TEN_SECONDLY_ROLLING_LIMIT\n : 1;\n } catch (Exception $e) {\n $retryAfter = 1;\n }\n\n $this->logger->warning('[HubSpot] Bulk add playback url to CRM failed', [\n 'reason' => $e->getMessage(),\n 'retry' => $retry,\n ]);\n\n if ($retry) {\n sleep($retryAfter);\n\n return $this->bulkAddPlaybackURLToDescriptionRequest($payload, false);\n }\n\n return false;\n }\n\n /**\n * Sometimes we have secondly rate limit error, then retry request after 1 second\n */\n public function searchCallByRecordingURLToken(string $playbackURLToken, bool $retry = true): array\n {\n $endpoint = 'https://api.hubapi.com/crm/v3/objects/calls/search';\n $payload = $this->payloadBuilder->generateSearchCallByTokenPayload($playbackURLToken);\n\n $this->logger->info('[HubSpot] CRM Search by playback URL token requested', [\n 'request' => $payload,\n ]);\n\n try {\n $response = $this->client->getInstance()->getClient()->request('POST', $endpoint, ['json' => ($payload)]);\n } catch (Exception $exception) {\n $this->logger->info('[HubSpot] Search by playback URL token failed', [\n 'playbackURLToken' => $playbackURLToken,\n 'reason' => $exception->getMessage(),\n 'retry' => $retry,\n ]);\n\n if ($retry) {\n sleep(1);\n\n return $this->searchCallByRecordingURLToken($playbackURLToken, false);\n }\n\n return [];\n }\n\n return empty($response['results']) ? [] : $response['results'][0];\n }\n\n /**\n * Generate transcription for the activity.\n */\n private function generateTranscription(Activity $activity): string\n {\n if (! $this->config->store_transcript) {\n // If sending transcription to activity toggle is disabled\n return '';\n }\n\n $transcriptionSegments = $this->transcriptionService->findTranscriptionByActivity($activity);\n\n if ($transcriptionSegments->isEmpty()) {\n return '';\n }\n\n $transcription = sprintf(\n '<p><strong>Transcript for %s</strong></p><p></p>',\n $activity->title ?? $activity->activity_title,\n );\n\n $roomOwnerParticipant = $activity->findParticipantRoomOwner();\n $roomOwnerParticipantId = $roomOwnerParticipant !== null\n ? $roomOwnerParticipant->getId()\n : null;\n\n\n $transcription .= $transcriptionSegments\n ->map(static function (array $transcriptionSegment) use ($roomOwnerParticipantId): string {\n $isOrganiser = $roomOwnerParticipantId === $transcriptionSegment['participantId']\n && $roomOwnerParticipantId !== null;\n $transcriptColor = $isOrganiser ? '#000000' : '#f0415a';\n\n return sprintf(\n '<span style=\"color: %s;\">%s | </span>%s',\n $transcriptColor,\n $transcriptionSegment['formattedStartsAt'],\n $transcriptionSegment['transcript'],\n );\n })\n ->implode('<br />');\n\n return $transcription;\n }\n\n /**\n * @param array<array{\n * id: string,\n * label: string,\n * value?: string,\n * }> $options\n *\n * @return FieldData[]\n */\n private function importOptions(Field $field, array $options): array\n {\n $fieldValues = [];\n $values = [];\n $sequence = 0;\n\n foreach ($options as $option) {\n $values[] = [\n 'value' => $option['value'] ?? $option['id'],\n 'label' => substr($option['label'], 0, 255),\n 'sequence' => $sequence++,\n ];\n }\n\n $fieldsToPurge = $field->values()->get()->pluck('value')->toArray();\n\n foreach ($values as $value) {\n $value['value'] = substr($value['value'], 0, 255);\n $fieldValues[] = $field->values()->updateOrCreate([\n 'value' => $value['value'],\n ], $value);\n\n // Remove this value from the ones we are going to purge.\n if (($key = array_search($value['value'], $fieldsToPurge, false)) !== false) {\n unset($fieldsToPurge[$key]);\n }\n }\n\n // Delete the old values that are no longer used.\n $field->values()->whereIn('value', $fieldsToPurge)->delete();\n\n return $fieldValues;\n }\n\n public function saveTranscriptionSummaryAsNote(\n ActivityContract $activity,\n string $title,\n string $body,\n ?string $objectId,\n ?NoteObject $noteObject = null,\n ): ?string {\n if ($noteObject === null || $objectId === null) {\n return null;\n }\n\n /** @var User $user */\n $user = $activity->getUser();\n\n $profile = $this->assignCrmOwner($user, $activity);\n if (! $profile instanceof Profile) {\n return null;\n }\n\n $timestamp = Carbon::now($user->getTimezone())->getTimestamp() * 1000;\n $engagement = [\n 'active' => true,\n 'ownerId' => $profile->getAttribute('crm_provider_id'),\n 'timestamp' => $timestamp,\n 'type' => 'NOTE',\n ];\n\n // Truncate Notes with max notes length because transcription text could be very long.\n $body = mb_strimwidth($body, 0, self::ENGAGEMENT_BODY_MAX_LENGTH);\n $metadata = [\n 'body' => $body,\n ];\n\n $associations = $this->convertActivityAssociations($activity);\n\n try {\n $hsActivityId = $this->client->createNote(\n body: $body,\n ownerId: $profile->getCrmProviderId(),\n timestamp: $timestamp,\n objectId: $objectId,\n noteObject: $noteObject,\n );\n\n $this->logCrmEngagementManipulation(self::ACTION_CREATE, $engagement, $metadata, $associations);\n\n $this->logger->info('[HubSpot] Saving Transcription Summary as Note', [\n 'activity' => $activity->getUuid(),\n 'crmActivity' => $hsActivityId,\n ]);\n\n return $hsActivityId;\n } catch (Exception $e) {\n Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function attachSummaryToActivity(ActivityContract $activity, string $summaryTitle, string $summaryContents): bool\n {\n $this->logger->info('[HubSpot] Attaching summary to activity', [\n 'activity' => $activity->getUuid(),\n 'summary_content' => $summaryContents,\n ]);\n\n if (! $activity instanceof Activity) {\n throw new InvalidArgumentException('Expected instance of Activity');\n }\n\n $summary = '<p><strong>' . $summaryTitle . '</strong></p>';\n $summary .= '<p>' . $summaryContents . '</p>';\n $metadata = $this->buildMetadataForSummaryUpdate($activity, $summary);\n\n try {\n $type = $this->matchActivityEngagementType($activity);\n $engagement = ['type' => $type];\n\n $this->client->updateEngagement($activity->getCrmProviderId(), $engagement, $metadata);\n } catch (Exception $e) {\n $this->logger->warning('[HubSpot] Update summary failed', [\n 'activity' => $activity->getUuid(),\n 'reason' => $e->getMessage(),\n ]);\n\n return false;\n }\n\n $this->logCrmEngagementManipulation(\n self::ACTION_UPDATE,\n ['crmId' => $activity->getCrmProviderId()],\n $metadata,\n );\n\n return true;\n }\n\n private function buildMetadataForSummaryUpdate(Activity $activity, string $summary): array\n {\n $descriptionField = $activity->getType() === Activity::TYPE_CONFERENCE ? 'internalMeetingNotes' : 'body';\n $engagement = $this->client->getEngagementData($activity->getCrmProviderId());\n // Meeting without internalMeetingNotes might mean it just does not have any notes;\n $description = $engagement['metadata'][$descriptionField] ?? null;\n\n if (empty($description)) {\n $data = $summary;\n } else {\n // avoid playbook url link to Jiminny being sent twice in the activity description\n $targetUrl = PlaybackUrlBuilder::build($activity);\n\n if (str_contains($description, $targetUrl)) {\n $jiminnyUrl = '<p><a href=\"' . $targetUrl . '\" title=\"Play at Jiminny\">Play at Jiminny</a></p>';\n $summary = str_replace($jiminnyUrl, '', $summary);\n\n $this->logger->info('[HubSpot] Summary modified', [\n 'activity' => $activity->getUuid(),\n 'target_url' => $jiminnyUrl,\n 'modified_summary_content' => $summary,\n ]);\n }\n\n $data = $description . '<p></p>' . $summary;\n }\n\n return [\n $descriptionField => $data,\n ];\n }\n\n public function fetchAndAssociateRelatedActivity(Activity $activity): ?Activity\n {\n return $this->syncRelatedActivityManager->fetchAndAssociateRelatedActivity($activity);\n }\n\n public function fetchRelatedActivity(Activity $activity): array\n {\n return [];\n }\n\n public function getDealsInBulk(array $dealIds): array\n {\n $payload = $this->payloadBuilder->getDealsInBulkPayload($dealIds);\n\n return $this->client->getPaginatedData($payload, 'deals');\n }\n\n /**\n * Extract deal IDs from HubSpot search response.\n *\n * @param array $hubspotResponse The raw HubSpot search API response.\n * @param bool $includeArchived Whether to include archived deals (default: false).\n *\n * @return string[] Array of deal IDs as strings.\n */\n public function extractDealIds(array $hubspotResponse, bool $includeArchived = false): array\n {\n if (empty($hubspotResponse['results'])) {\n return [];\n }\n\n return array_values(\n array_map(\n fn ($deal) => $deal['id'],\n array_filter(\n $hubspotResponse['results'],\n fn ($deal) => $includeArchived || empty($deal['archived'])\n )\n )\n );\n }\n\n public function matchActivityEngagementType(Activity $activity): string\n {\n return match ($activity->getType()) {\n Activity::TYPE_CONFERENCE => self::TYPE_MEETING,\n Activity::TYPE_SOFTPHONE, Activity::TYPE_SOFTPHONE_INBOUND => self::TYPE_CALL,\n default => self::TYPE_NOTE,\n };\n }\n\n private function assignCrmOwner(User $user, ActivityContract $activity): ?Profile\n {\n $profile = $user->getProfile();\n if ($profile instanceof Profile) {\n return $profile;\n }\n\n $this->logger->info('[HubSpot] Unable to save summary. No profile', [\n 'activity' => $activity->getUuid(),\n ]);\n\n return null;\n }\n\n private static function getDealsPipelinesEndpoint(): string\n {\n return self::API_URL . self::ENDPOINT_PIPELINES . self::PIPELINE_OBJECT_TYPE_DEALS;\n }\n\n public function verifyTaskExists(Activity $activity): bool\n {\n $crmProviderId = $activity->getCrmProviderId();\n $cacheKey = \"crm_task_exists:{$this->config->getId()}:$crmProviderId\";\n\n return Cache::remember($cacheKey, self::TASK_VERIFICATION_CACHE_TTL, function () use ($crmProviderId) {\n try {\n $engagement = $this->client->getEngagementData($crmProviderId);\n\n return ! empty($engagement);\n } catch (HttpNotFoundException|BadRequest) {\n // Engagement not found in CRM - this is expected and permanent\n $this->logger->info('[Hubspot] Engagement not found during verification', [\n 'engagement_id' => $crmProviderId,\n 'config_id' => $this->config->getId(),\n ]);\n\n return false;\n }\n // Let other exceptions (network errors, rate limits, etc.) bubble up for retry\n });\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.011968086,"top":0.047885075,"width":0.024268618,"height":0.024740623},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-229854141067132447
|
-465898686617872281
|
visual_change
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
A
1
Select All
5190
5190
0
4e3f2289-a3d2-5235-b410-b94ebb547490
4e3f2289-a3d2-5235-b410-b94ebb547490
Umbrella Corp
2
2
0
2
2
0
1212213464
1212213464
Umbrella Corp
430
430
0
579583316
579583316
Umbrella Corp
Umbrella Corp
Umbrella Corp
Umbrella Corp
[PHONE]
[PHONE]
Umbrella Corp
<null>
<null>
Umbrella Corp
<null>
<null>
Umbrella Corp
umbrellacorp.com
umbrellacorp.com
Umbrella Corp
/abae74b8-bfa8-4383-9a7f-89f4bf2bdbb4/avatars/1212213464.png
/abae74b8-bfa8-4383-9a7f-89f4bf2bdbb4/avatars/1212213464.png
Umbrella Corp
<null>
<null>
Umbrella Corp
0
0
0
<null>
<null>
Umbrella Corp
2026-03-30 06:44:25
2026-03-30 06:44:25
Umbrella Corp
2019-02-01 15:39:53
2019-02-01 15:39:53
Umbrella Corp
2026-03-30 06:44:25
2026-03-30 06:44:25
Umbrella Corp
id = 5190
Editor
1 row
Reload Page
Table Result Auto Refresh
Cancel Running Statements
Add Row
Delete Row
Revert Selected
Preview Pending Changes
Submit
Tx: Auto
DDL
Find on Current Page
Table Result Local Filter
Record View
Table Coloring Options
Show Geo Viewer
Show Chart
CSV
Export Data…
Copy to Database…
Compare Data
View as
Show Options Menu
Sync Changes
Hide This Notification
Code changed:
Hide
7
48
1
33
1
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Services\Crm\Hubspot;
use Carbon\Carbon;
use Exception;
use Generator;
use GuzzleHttp\Exception\RequestException;
use Illuminate\Support\Facades\Cache;
use InvalidArgumentException;
use Jiminny\Contracts\Repositories\TeamRepository;
use Jiminny\Contracts\Services\Crm\ClientInterface;
use Jiminny\Contracts\Services\Crm\FetchRelatedActivityInterface;
use Jiminny\Contracts\Services\Crm\LayoutManagementInterface;
use Jiminny\Contracts\Services\Crm\MatchCrmEntitiesInterface;
use Jiminny\Contracts\Services\Crm\Provider\HubspotInterface;
use Jiminny\Contracts\Services\Crm\RemoteEntityLookupInterface;
use Jiminny\Contracts\Services\Crm\RemoteEntityManipulationInterface;
use Jiminny\Contracts\Services\Crm\SavePlaybackLinkToCrmInterface;
use Jiminny\Contracts\Services\Crm\SendSummaryToCrmInterface;
use Jiminny\Contracts\Services\Crm\SettingsInterface;
use Jiminny\Contracts\Services\Crm\SyncCrmEntitiesInterface;
use Jiminny\Contracts\Services\Crm\SyncCrmMetadataInterface;
use Jiminny\Contracts\Services\Crm\VerifyTaskExistsInterface;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\HttpNotFoundException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Account;
use Jiminny\Models\Activity;
use Jiminny\Models\Contact;
use Jiminny\Models\Contracts\ActivityContract;
use Jiminny\Models\Crm\BusinessProcess;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldData;
use Jiminny\Models\Crm\Layout;
use Jiminny\Models\Crm\Profile;
use Jiminny\Models\Lead;
use Jiminny\Models\Opportunity;
use Jiminny\Models\Participant;
use Jiminny\Models\Playbook;
use Jiminny\Models\SocialAccount;
use Jiminny\Models\Stage;
use Jiminny\Models\User;
use Jiminny\Repositories\Crm\CrmEntityRepository;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Repositories\Crm\ProfileRepository;
use Jiminny\Repositories\ParticipantRepository;
use Jiminny\Services\Avatar\ProspectPhotoPathService;
use Jiminny\Services\Crm\BaseService;
use Jiminny\Services\Crm\Hubspot\Actions\SyncArchivedProfilesAction;
use Jiminny\Services\Crm\Hubspot\Fields\ValueNormalizer;
use Jiminny\Services\Crm\Hubspot\ServiceTraits\OpportunitySyncTrait;
use Jiminny\Services\Crm\Hubspot\ServiceTraits\SyncCrmEntitiesTrait;
use Jiminny\Services\Crm\Hubspot\ServiceTraits\SyncFieldsTrait;
use Jiminny\Services\Crm\Hubspot\ServiceTraits\WriteCrmTrait;
use Jiminny\Services\Crm\MatchDomainByEmailInterface;
use Jiminny\Services\Crm\OpportunitySyncStrategyResolver;
use Jiminny\Services\Crm\ResolveCompanyNameByEmailTrait;
use Jiminny\Utils\PlaybackUrlBuilder;
use Sentry;
use SevenShores\Hubspot\Exceptions\BadRequest;
use Throwable;
use UnexpectedValueException;
/**
* @phpstan-type CrmFieldDefinition array{
* name: string,
* label: string,
* description: string,
* type: string,
* fieldType: string,
* hidden: bool,
* showCurrencySymbol: bool,
* options: array<array{
* id: string,
* label: string,
* value?: string,
* }
*/
class Service extends BaseService implements
HubspotInterface,
SyncCrmEntitiesInterface,
SyncCrmMetadataInterface,
SendSummaryToCrmInterface,
MatchDomainByEmailInterface,
SavePlaybackLinkToCrmInterface,
RemoteEntityManipulationInterface,
FetchRelatedActivityInterface,
LayoutManagementInterface,
SettingsInterface,
MatchCrmEntitiesInterface,
RemoteEntityLookupInterface,
VerifyTaskExistsInterface
{
use ResolveCompanyNameByEmailTrait;
use SyncCrmEntitiesTrait;
use WriteCrmTrait;
use SyncFieldsTrait;
use OpportunitySyncTrait;
private const int ENGAGEMENT_BODY_MAX_LENGTH = 65536;
private const string LOG_DATE_FORMAT = 'Y-m-d H:i:s';
private const int BATCH_UPDATE_LIMIT = 100;
private const string TEN_SECONDLY_ROLLING_POLICY = 'TEN_SECONDLY_ROLLING';
private const int TEN_SECONDLY_ROLLING_LIMIT = 10;
private const string CALLS_SEARCH_ENDPOINT = '[URL_WITH_CREDENTIALS] ClientInterface|Client
*/
protected $client;
protected OpportunitySyncStrategyResolver $opportunitySyncStrategyResolver;
protected CrmEntityRepository $crmEntityRepository;
protected ProspectPhotoPathService $prospectPhotoPathService;
private SyncFieldAction $syncFieldAction;
private PayloadBuilder $payloadBuilder;
private SyncRelatedActivityManager $syncRelatedActivityManager;
private SyncArchivedProfilesAction $syncArchivedProfilesAction;
private WebhookSyncBatchProcessor $batchProcessor;
public function __construct(
Client $client,
SyncFieldAction $syncFieldAction,
PayloadBuilder $payloadBuilder,
ProspectPhotoPathService $prospectPhotoPathService,
SyncArchivedProfilesAction $syncArchivedProfilesAction,
WebhookSyncBatchProcessor $batchProcessor,
) {
parent::__construct();
$this->client = $client;
$this->syncFieldAction = $syncFieldAction;
$this->prospectPhotoPathService = $prospectPhotoPathService;
$this->payloadBuilder = $payloadBuilder;
$this->syncArchivedProfilesAction = $syncArchivedProfilesAction;
$this->batchProcessor = $batchProcessor;
$this->opportunitySyncStrategyResolver = app(OpportunitySyncStrategyResolver::class, [
'client' => $this->client,
]);
$this->syncRelatedActivityManager = app(SyncRelatedActivityManager::class, [
'client' => $this->client,
'payloadBuilder' => $this->payloadBuilder,
'logger' => $this->logger,
]);
$this->crmEntityRepository = app(CrmEntityRepository::class);
$this->dealFieldsService = app(DealFieldsService::class);
}
public function getDisplayName(): string
{
return 'HubSpot';
}
protected function getOAuthAccount(User $user): ?SocialAccount
{
// In this case, the Account Owner is always the connection for any API operations.
$owner = $user->team->owner;
return $owner->getSocialAccount(SocialAccount::PROVIDER_HUBSPOT);
}
public function getClient(): Client
{
/** @var Client */
return $this->client;
}
/**
* Convert raw field data into a format compatible with CRM APIs.
*
* @param bool $internal Direction of the conversion.
* True is pulling from CRM, false normalize before sending to CRM.
*/
public function normalizeValue(string $fieldType, string $fieldValue, bool $internal = false): string
{
return ValueNormalizer::normalize(
fieldType: $fieldType,
fieldValue: $fieldValue,
isInbound: $internal,
);
}
/**
* @inheritdoc
*/
public function getDefaultFields(string $activityType): array
{
$fields = [];
if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {
$defaultFields = FieldDefinitions::defaultTaskFields();
// This lazy creates these fields if not already setup.
foreach ($defaultFields as $defaultField) {
$fields[] = $this->config->fields()->firstOrCreate($defaultField);
}
}
return $fields;
}
/**
* @inheritdoc
*/
public function getDefaultActivityField(string $activityType): Field
{
/** @var Field $activityField */
$activityField = $this->config->fields()->where([
'crm_provider_id' => 'activityType',
'object_type' => $activityType,
])->first();
return $activityField;
}
/**
* @inheritdoc
*/
public function getSupportedPlaybookTypes(): array
{
return [Playbook::ACTIVITY_TYPE_TASK];
}
/**
* @inheritdoc
*/
public function getDefaultActivityLayoutFields(string $activityType, string $layoutType): array
{
$fields = [];
if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {
// Outcome should always be provided calls/meetings.
$fieldData = [
[
'crm_provider_id' => $layoutType === Layout::TYPE_SOFTPHONE_SUMMARY ? 'disposition' : 'meetingOutcome',
'object_type' => Field::OBJECT_TASK,
],
];
foreach ($fieldData as $data) {
$field = $this->config->fields()->where($data)->first();
// Only add the field if it is created, which it should be.
if ($field) {
$fields[] = $field;
}
}
}
return $fields;
}
public function getDealInsightsFields(): array
{
return FieldDefinitions::dealInsightsFields();
}
protected function getDefaultFollowupLayoutFields(string $activityType): array
{
$fields = [];
$fieldRepo = app(FieldRepository::class);
$fieldData = FieldDefinitions::followupFieldsFilter();
foreach ($fieldData as $data) {
$field = $fieldRepo->findOneConfigurationFieldByProperties($this->config, $data);
// Only add the field if it is created, which it should be.
if ($field) {
$fields[] = $field;
}
}
return $fields;
}
/**
* @inheritdoc
*/
public function syncField(Field $field): void
{
switch ($field->object_type) {
case Field::OBJECT_ACCOUNT:
$crmField = $this->client->getInstance()->companyProperties()->get($field->crm_provider_id);
break;
case Field::OBJECT_CONTACT:
$crmField = $this->client->getInstance()->contactProperties()->get($field->crm_provider_id);
break;
case Field::OBJECT_OPPORTUNITY:
$crmField = $this->client->getInstance()->dealProperties()->get($field->crm_provider_id);
break;
case Field::OBJECT_TASK:
$this->syncSingleTaskField($field);
return;
default:
return;
}
$this->syncFieldAction->execute($field, $crmField->toArray());
}
/**
* @param array<array{
* id:string,
* label:string,
* value?:string
* }> $options
*
* @throws CrmException
*
* @return FieldData[]
*
*/
public function importPicklistValues(
Field $field,
array $options = [['id' => '', 'label' => '', 'value' => '']],
): array {
if (! empty($options[0]['id']) || ! empty($options[0]['value'])) {
// We already have the options, no need to fetch them again
return $this->importOptions($field, $options);
}
$options = [];
switch ($field->getObjectType()) {
case Field::OBJECT_ACCOUNT:
$options = $this->getClient()->fetchPropertyOptions('company', $field->getCrmProviderId());
break;
case Field::OBJECT_CONTACT:
$options = $this->getClient()->fetchPropertyOptions('contact', $field->getCrmProviderId());
break;
case Field::OBJECT_OPPORTUNITY:
// Hubspot has different endpoint for stages
$options = $this->getClient()->fetchOpportunityFieldOptions($field);
break;
case Field::OBJECT_TASK:
if ($field->getCrmProviderId() === 'disposition') {
$options = $this->getClient()->fetchDispositionFieldOptions();
} elseif (in_array($field->getCrmProviderId(), ['meetingOutcome', 'activityType'])) {
$options = $this->getClient()->fetchMeetingOutcomeFieldOptions($field);
}
break;
default:
$this->logger->warning('Invalid object type', [
'object_type' => $field->getObjectType(),
'field_id' => $field->getId(),
]);
throw new CrmException('Invalid object type');
}
return $this->importOptions($field, $options);
}
/**
* @inheritdoc
*/
public function importStages(?array $types = null, ?string $missingStageName = null): ?Stage
{
$missingStage = null;
try {
// Use the HubSpot API client instead of the SDK crmPipelines() method
$endpoint = self::getDealsPipelinesEndpoint();
$pipelinesResponse = $this->client->getInstance()->getClient()->request('GET', $endpoint);
$pipelines = $pipelinesResponse->data->results;
} catch (RequestException|BadRequest $exception) {
throw $exception;
}
foreach ($pipelines as $pipeline) {
$stages = [];
// We create a business process to contain the pipeline, and store all stages against it.
$p = ResponseNormalize::normalizePipeline($pipeline);
// Create/update business process for this pipeline
$businessProcess = $this->config->businessProcesses()->updateOrCreate([
'crm_provider_id' => $p['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($p['label'], 0, 150),
'type' => BusinessProcess::TYPE_OPPORTUNITY,
'is_selectable' => $p['active'],
]);
// A record type is really a clone of the business process, used to store which record uses which pipeline.
// Create/update record type clone
$this->config->recordTypes()->updateOrCreate([
'crm_provider_id' => $p['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($p['label'], 0, 150),
'is_selectable' => $p['active'],
'business_process_id' => $businessProcess->id ?? null,
]);
// Stages - fetch all existing stages upfront to avoid N+1 queries
$existingStages = $this->config->stages()
->withTrashed()
->where('type', Stage::TYPE_OPPORTUNITY)
->get()
->keyBy('crm_provider_id');
foreach ($p['stages'] as $dealStage) {
$s = ResponseNormalize::normalizeDealStage($dealStage);
/** @var ?Stage $existingStage */
$existingStage = $existingStages->get($s['id']);
// Restore soft-deleted stages that are now active in HubSpot
if ($existingStage?->trashed() && $s['active']) {
$existingStage->restore();
}
// Upsert stage (updates soft-deleted records without restoring them)
$stage = $this->config->stages()->withTrashed()->updateOrCreate([
'crm_provider_id' => $s['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($s['label'], 0, 50),
'label' => mb_strimwidth($s['label'], 0, 191),
'type' => Stage::TYPE_OPPORTUNITY,
'sequence' => $s['displayOrder'],
'is_selectable' => $s['active'],
'probability' => $s['probability'] * 100,
]);
if ($missingStageName === $s['id']) {
$missingStage = $stage;
}
$stages[] = $stage->id;
}
$businessProcess->stages()->sync($stages);
}
return $missingStage;
}
/**
* @inheritdoc
*/
public function syncOrganization(): void
{
try {
$endpoint = '[URL_WITH_CREDENTIALS]
*/
public function find(string $name, array $scopes): array
{
$count = $this->limit ?? 20;
$offset = $this->offset ?? 0;
/** @var array<int, array<string, mixed>> */
return Cache::remember(
key: $this->team->getId() . $name . $count . $offset,
ttl: 300,
callback: function () use ($name, $offset, $count): array {
$data = [];
// Use the new V3 API to find contacts based on additional fields.
foreach (['companies', 'contacts'] as $objectType) {
$endpoint = '[URL_WITH_CREDENTIALS]
*/
public function findOpportunities(?string $crmAccountId, ?string $crmContactId, ?int $userId = null): array
{
$data = [];
$ownerData = [];
$ownerId = null;
if ($crmAccountId === null) {
return $data;
}
if ($userId) {
$profileRepository = app(ProfileRepository::class);
$profile = $profileRepository->findProfileByUserId($this->config, $userId);
$ownerId = $profile instanceof Profile ? $profile->getCrmProviderId() : null;
}
$closedStages = $this->getClosedDealStages();
$payload = $this->payloadBuilder->generateOpportunitiesSearchPayload(
$this->config,
$crmAccountId,
$closedStages,
);
$results = $this->client->getPaginatedData($payload, 'deals');
foreach ($results['results'] as $object) {
$properties = $object['properties'];
$amount = null;
if (empty($properties['amount']) === false) {
$currency = $properties['deal_currency_code'] ?? $this->config->default_currency;
// Values can contain commas and any junk so strip them.
$value = (float) preg_replace('/[^\d.]/', '', $properties['amount']);
$amount = formatCurrency($value, $currency);
}
$businessProcess = $this->config
->businessProcesses()
->where('crm_provider_id', $properties['pipeline'])
->first();
if ($businessProcess === null) {
// Import it.
$stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $properties['dealstage']);
$businessProcess = $this->config
->businessProcesses()
->where('crm_provider_id', $properties['pipeline'])
->first();
} else {
$stage = $businessProcess
->stages()
->where('crm_provider_id', $properties['dealstage'])
->where('type', Stage::TYPE_OPPORTUNITY)
->first();
if ($stage === null) {
// Import it.
$stage = $this->importStages(null, $properties['dealstage']);
}
}
$recordType = null;
if ($businessProcess) {
$recordType = $businessProcess->recordTypes()->first();
}
$isWon = in_array($properties['dealstage'], $closedStages['won']);
$isLost = in_array($properties['dealstage'], $closedStages['lost']);
$record = [
'crmId' => $object['id'],
'name' => $properties['dealname'] ?? 'Unknown Deal',
'value' => $amount,
'won' => $isWon,
'closed' => $isWon || $isLost,
'stage' => [
'id' => $stage?->getUuid() ?? '',
'name' => $stage?->getName() ?? '',
],
];
if ($recordType) {
$record += [
'recordType' => [
'id' => $recordType->id_string,
'name' => $recordType->name,
],
];
}
if ($ownerId && isset($properties['hubspot_owner_id']) && $properties['hubspot_owner_id'] === $ownerId) {
$ownerData[] = $record;
}
$data[] = $record;
}
if (! empty($ownerData)) {
return $ownerData;
}
return $data;
}
/**
* @inheritdoc
*/
public function getTasks(?string $objectType, string $objectId, ?string $opportunityId): array
{
$data = [];
switch ($objectType) {
case 'contact':
$hsObject = 'contact';
break;
case 'account':
$hsObject = 'company';
break;
default:
// This is a hack to prioritise and override a contact/company with a deal.
if ($opportunityId) {
$hsObject = 'deal';
$objectId = $opportunityId;
} else {
throw new InvalidArgumentException('Object type not supported.');
}
}
$engagementTypes = ['meetings', 'tasks'];
foreach ($engagementTypes as $engagementType) {
$payload = $this->payloadBuilder->getLinkToTaskPayload($hsObject, $objectId, $engagementType);
$this->logger->info('[HubSpot] CRM Search requested', [
'request' => $payload,
]);
$engagements = $this->client->getPaginatedData($payload, $engagementType);
foreach ($engagements['results'] as $engagement) {
if ($engagementType == 'meetings') {
$title = $engagement['properties']['hs_meeting_title'] ?? 'Scheduled meeting';
} elseif ($engagementType == 'tasks') {
$title = $engagement['properties']['hs_task_subject'];
} else {
$title = 'Scheduled meeting';
}
$data[] = [
'crmId' => $engagement['id'],
'subject' => $title,
'due' => $engagement['properties']['hs_timestamp'],
'type' => $engagement['properties']['hs_activity_type'] ?? null,
];
}
}
usort($data, function ($item1, $item2) {
return $item2['due'] <=> $item1['due'];
});
return $data;
}
/**
* Try to find CRM Objects using email address
*
* @return null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
* }
*/
public function matchExactlyByEmail(string $email, ?int $userId = null): ?array
{
$contactProperties = [
'email',
'firstname',
'lastname',
'country',
'phone',
'mobilephone',
'jobtitle',
'hubspot_owner_id',
'associatedcompanyid',
'photo',
];
$contact = null;
$account = null;
try {
$hsContact = $this->getClient()->getContactByEmail($email, $contactProperties);
if ($hsContact) {
$contact = $this->importContact($hsContact);
$account = $contact->account;
}
$data = $this->convertCrmData($contact, $account, $userId);
return ! empty(array_filter($data)) ? $data : null;
} catch (BadRequest $e) {
$this->logger->warning('[HubSpot] Search failed', [
'team_id' => $this->team->getId(),
'search_identifier' => $email,
'reason' => $e->getMessage(),
]);
}
return null;
}
public function getDomain(string $email): ?string
{
return $this->getDomainFromEmail($email);
}
/**
* Try to find CRM objects using domain name of the email address
*
* @return null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
* }
*/
public function matchByDomain(string $domain, ?int $userId = null): ?array
{
$companyName = $domain;
// Try to find a company matching their email domain.
$companyProperties = [
'country',
'phone',
'name',
'hs_avatar_filemanager_key',
'industry',
'hubspot_owner_id',
'domain',
];
try {
$hsAccounts = $this->client
->getInstance()
->companies()
->searchByDomain($companyName, $companyProperties);
} catch (Throwable $e) {
$this->logger->info('[HubSpot] Search failed', [
'error' => $e->getMessage(),
'domain' => $domain,
]);
return null;
}
$account = null;
// If there are multiple accounts, don't guess, we'll ask later.
if (\count($hsAccounts->data->results) === 1) {
// Persist this remote object.
$account = $this->syncAccount($hsAccounts->data->results[0]->companyId);
}
$data = $this->convertCrmData(null, $account, $userId);
return ! empty(array_filter($data)) ? $data : null;
}
/**
* @return array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
* }
*/
protected function convertCrmData(?Contact $contact, ?Account $account, ?int $userId = null): array
{
$countryCode = null;
if ($contact && $contact->country_code) {
$countryCode = $contact->country_code;
} elseif ($account && $account->country_code) {
$countryCode = $account->country_code;
}
try {
$hsOpportunities = $this->findOpportunities(
$account ? $account->crm_provider_id : null,
$contact ? $contact->crm_provider_id : null,
$userId
);
} catch (Exception $e) {
$hsOpportunities = [];
}
// If there are multiple opportunities, don't guess, we'll ask later.
$opportunity = null;
$stage = null;
if (! empty($hsOpportunities)) {
// Persist this remote object.
$opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);
$stage = $opportunity?->getStage();
}
return [
null,
$account,
$opportunity,
$contact,
$stage,
$countryCode,
];
}
protected function getCacheKey(string $object, ?int $userId = null): ?string
{
$key = $this->team->getId() . $object;
$keySuffix = $this->getOwnerKeySuffix($userId);
return $key . $keySuffix;
}
private function getOwnerKeySuffix(?int $userId = null): string
{
return $userId === null ? '' : (string) $userId;
}
/**
* @return null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
*}
*/
public function matchByPhone(string $phone, ?string $rawPhoneNumber = null, ?int $userId = null): ?array
{
if (str_contains($phone, '**')) {
return null;
}
// trim all whitespaces if present so the lookup doesn't fail
$phone = str_replace(' ', '', $phone);
// Check if the user is internal.
if ($this->isPhoneNumberOfTeamMember($phone)) {
return null;
}
$response = $this->searchForPhoneNumber($phone);
if (empty($response)) {
return null;
}
// This would ideally importContact instead but the response type differs.
$contact = $this->findAndSyncContact($response['results'][0]['id']);
if (! $contact instanceof Contact) {
return null;
}
$account = $contact->account;
$countryCode = $contact->country_code ?? $account->country_code ?? null;
try {
$hsOpportunities = $this->findOpportunities(
$account?->crm_provider_id,
$contact->crm_provider_id,
$userId
);
} catch (Exception $e) {
$hsOpportunities = [];
}
$opportunity = null;
$stage = null;
try {
if (! empty($hsOpportunities)) {
// Persist this remote object.
$opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);
$stage = $opportunity?->getStage();
}
} catch (Exception $e) {
$this->logger->debug('[HubSpot] Opportunity failed to sync.', [
'reason' => $e->getMessage(),
]);
}
return [
null,
$account,
$opportunity,
$contact,
$stage,
$countryCode,
];
}
private function isPhoneNumberOfTeamMember(string $phone): bool
{
$teamRepository = app(TeamRepository::class);
$user = $teamRepository->findTeamMemberByPhone($this->team, $phone);
if ($user instanceof User) {
return true;
}
return false;
}
private function findAndSyncContact(string $crmId): ?Contact
{
try {
return $this->syncContact($crmId);
} catch (Exception $exception) {
$this->logger->info('[HubSpot] Phone match failed', [
'reason' => $exception->getMessage(),
]);
return null;
}
}
private function hasResults(array $response): bool
{
return isset($response['total']) && is_numeric($response['total']) && $response['total'] > 0;
}
private function searchForPhoneNumber(string $phone): array
{
// Normalizes the provided phone number for the API search.
$normalizedPhone = $this->normalizePhoneNumber($phone);
$payload = $this->payloadBuilder->generatePhoneSearchPayload($normalizedPhone);
$this->logger->info('[HubSpot] Phone match search triggered', [
'phone' => $phone,
'normalizedPhone' => $normalizedPhone,
'payload' => $payload,
]);
$response = $this->handlePhoneSearchRequest($normalizedPhone, $payload);
if (! $this->hasResults($response)) {
$nationalPhone = preg_replace('/\D/', '', phone_national(null, $phone));
$payload = $this->payloadBuilder->generatePhoneSearchPayload($nationalPhone);
$this->logger->info('[HubSpot] Phone match national number search triggered', [
'phone' => $phone,
'nationalPhone' => $nationalPhone,
'payload' => $payload,
]);
$response = $this->handlePhoneSearchRequest($phone, $payload);
}
if (! $this->hasResults($response)) {
$payload = $this->payloadBuilder->generatePhoneSearchPayload($normalizedPhone, true);
$this->logger->info('[HubSpot] Phone match alternative search triggered', [
'phone' => $phone,
'normalizedPhone' => $normalizedPhone,
'payload' => $payload,
]);
$response = $this->handlePhoneSearchRequest($phone, $payload);
}
return $this->hasResults($response) ? $response : [];
}
private function handlePhoneSearchRequest(string $phone, array $payload): array
{
$endpoint = '[URL_WITH_CREDENTIALS] null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
* }
*/
public function matchByName(string $name, ?int $userId = null): ?array
{
// Don't waste time searching for single character strings.
if (\strlen($name) <= 1) {
return null;
}
$cacheKey = $this->getCacheKey($name, $userId);
$result = Cache::remember($cacheKey, 60, function () use ($name, $userId) {
$payload = $this->payloadBuilder->generateSearchContactsByNamePayload(
$name,
$this->getContactFields()
);
$hsContacts = $this->client->getPaginatedData($payload, 'contact');
if (empty($hsContacts['results'])) {
return false;
}
$contact = $this->importContact($hsContacts['results'][0]);
if ($contact === null) {
return false;
}
$account = $contact->account;
$countryCode = $contact->country_code ?? $account->country_code ?? null;
try {
$hsOpportunities = $this->findOpportunities(
$account ? $account->crm_provider_id : null,
$contact->crm_provider_id,
$userId
);
} catch (Exception $e) {
$hsOpportunities = [];
}
$opportunity = null;
$stage = null;
if (! empty($hsOpportunities)) {
// Persist this remote object.
$opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);
$stage = $opportunity?->getStage();
}
return [
null,
$account,
$opportunity,
$contact,
$stage,
$countryCode,
];
});
return is_array($result) ? $result : null;
}
private function convertActivityAssociations(Activity $activity): array
{
return [
'contactIds' => $this->getParticipantsIds($activity),
'companyIds' => $activity->hasAccount() ? [$activity->account->crm_provider_id] : [],
'dealIds' => $activity->hasOpportunity() ? [$activity->opportunity->crm_provider_id] : [],
'ownerIds' => [],
];
}
private function getParticipantsIds(Activity $activity): array
{
$attendees = [];
$participantRepository = app(ParticipantRepository::class);
$participants = $participantRepository->getParticipantsWhoEnteredMeeting($activity);
foreach ($participants as $participant) {
if ($participant->user_id || $participant->isCoach()) {
continue;
}
$contact = $participant->contact()->first();
if ($contact && $contact->crm_provider_id) {
$attendees[] = $contact->crm_provider_id;
} else {
if (! empty($participant->name)) {
$attendeeData = $this->fetchMissingAttendeeInfo($participant);
}
if (! empty($attendeeData['id'])) {
$attendees[] = $attendeeData['id'];
}
}
}
if ($activity->hasContact()) {
$attendees[] = $activity->contact->crm_provider_id;
}
return array_unique($attendees);
}
private function fetchMissingAttendeeInfo(Participant $participant): array
{
// Check if we need to look inside an account context.
$activity = $participant->getActivity();
$companyId = $activity->hasAccount() ? $activity->getAccount()->crm_provider_id : null;
// First check the local data.
/** @var Contact[] $contacts */
$contacts = $this->team->contacts()
->with('account')
->where('name', $participant->name)
->whereNotNull('email')
->get();
foreach ($contacts as $contact) {
// If we have a company in scope, check the contact is associated to it.
if (
$companyId !== null
&& ($contact->account_id === null || $companyId !== $contact->account->crm_provider_id)
) {
continue;
}
return [
'id' => $contact->crm_provider_id,
'email' => $contact->email,
];
}
$payload = $this->generateNameSearchPayload($participant->name, 0, 20);
try {
$response = $this->client->getNewInstance()->crm()->contacts()->searchApi()->doSearch($payload);
// TODO add some logic to choose the most suitable contact if multiple
foreach ($response['results'] as $object) {
$properties = $object['properties'];
if (empty($object['properties']) === false) {
// Check the company matches the contact.
// Todo: Move this check inside the API search.
if ($companyId !== null && $companyId !== $properties['associatedcompanyid']) {
continue;
}
return [
'id' => $object['id'],
'email' => $properties['email'],
];
}
}
} catch (Exception $e) {
$this->logger->warning('[' . $this->getDisplayName() . '] Search failed', [
'teamId' => $this->team->id_string,
'request' => $payload,
'reason' => $e->getMessage(),
]);
}
return [];
}
/**
* Store transcripts as note engagement.
*
* @throws Exception
*/
public function createTranscriptNotes(Activity $activity): void
{
// For HS no need to check if Crm profile - Log Notes field is enabled
// We only check if store_transcript toggle is enabled on crm profile.
$engagement = [
'active' => true,
'ownerId' => $this->profile->crm_provider_id,
'timestamp' => $activity->created_at->tz($activity->user->timezone)->getTimestamp() * 1000,
'type' => 'NOTE',
];
// Generate activity transcription.
$transcriptionData = $this->generateTranscription($activity);
// Truncate Notes with max notes length because transcription text could be very long.
$transcripts = mb_strimwidth($transcriptionData, 0, static::ENGAGEMENT_BODY_MAX_LENGTH);
$metadata = [
'body' => $transcripts,
];
$associations = $this->convertActivityAssociations($activity);
try {
$hsEngagement = $this->client
->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
$this->logCrmEngagementManipulation(self::ACTION_CREATE, $engagement, $metadata, $associations);
$noteId = $hsEngagement->data->engagement->id;
// Store crm logged id in transcription.
$transcription = $activity->getTranscription();
$transcription->crm_activity_id = $noteId;
$transcription->save();
} catch (Exception $e) {
Sentry::captureException($e);
}
}
/*
* @inheritdoc
*/
public function updateRecord(string $objectType, string $objectId, array $data, array $headers = []): void
{
$payload = [
'properties' => $data,
];
try {
switch ($objectType) {
case FieldData::OBJECT_OPPORTUNITY:
$this->client->getNewInstance()->crm()->deals()->basicApi()->update($objectId, $payload);
break;
case FieldData::OBJECT_CONTACT:
$this->client->getNewInstance()->crm()->contacts()->basicApi()->update($objectId, $payload);
break;
case FieldData::OBJECT_ACCOUNT:
$this->client->getNewInstance()->crm()->companies()->basicApi()->update($objectId, $payload);
break;
case FieldData::OBJECT_TASK:
// Endpoint for Engagements not ready
$engagements = [
'type' => 'TASK',
];
$metadata = $data;
$this->client->getInstance()->engagements()->update($objectId, $engagements...
|
3853
|
NULL
|
NULL
|
NULL
|
|
4975
|
177
|
43
|
2026-05-07T14:42:10.102152+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-07/1778 /Users/lukas/.screenpipe/data/data/2026-05-07/1778164930102_m1.jpg...
|
Firefox
|
Illuminate\Queue\MaxAttemptsExceededException: Jim Illuminate\Queue\MaxAttemptsExceededException: Jiminny\Jobs\Activity\DeleteTeamChurnData has been attempted too many times. — jiminny — app — Work...
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 3 Q2 - Platform Team - Scrum Board Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
SevenShores\Hubspot\Exceptions\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your secondly limit.","errorType":"RATE_LIMIT
SevenShores\Hubspot\Exceptions\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your secondly limit.","errorType":"RATE_LIMIT
Service-Desk - Queues - Platform team - Service space - Jira
Service-Desk - Queues - Platform team - Service space - Jira
Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app
Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app
Illuminate\Queue\MaxAttemptsExceededException: Jiminny\Jobs\Activity\DeleteTeamChurnData has been attempted too many times. — jiminny — app
Illuminate\Queue\MaxAttemptsExceededException: Jiminny\Jobs\Activity\DeleteTeamChurnData has been attempted too many times. — jiminny — app
Close tab
Pull requests · jiminny/app
Pull requests · jiminny/app
Userpilot | Ask Jiminny Report Generated
Userpilot | Ask Jiminny Report Generated
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
Jiminny
Jiminny
Search the CRM - HubSpot docs
Search the CRM - HubSpot docs
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Skip to main content
Skip to main content
Toggle organization menu
Issues
Issues
Explore
Explore
Dashboards
Dashboards
Monitors
Monitors
Settings
Settings
Try Business
What's New
Help
[EMAIL]
Issues
Expand
Feed
Feed
Errors & Outages
Errors & Outages
Breached Metrics
Breached Metrics
Warnings
Warnings
User Feedback
User Feedback
Autofix
Autofix
Recently Run
Recently Run
All Views
All Views
Configure
Alerts Moved
Alerts
Moved
Issues
Issues
View Project Details
APP-1902
Ask Seer
Ask Seer
/
Give Feedback
Illuminate\Queue\MaxAttemptsExceededException
View events
Events (total)
View affected users
Users (90d)
Level: Error
Jiminny\Jobs\Activity\DeleteTeamChurnData has been attempted too many times.
260K
44
Ongoing
/app/Queue/Worker/Worker.php in Jiminny\Queue\Worker\Worker::process
Resolve
Resolve
More resolve options
Archive
Archive
Archive options
Subscribe
Share
More Actions
Priority
Modify issue priority
High
Assignee
Modify issue assignee
Vasil Vasilev
All Envs
All Envs
90D
90D
Add a search term
Add a search term
Close sidebar
Toggle graph series - Events
Events
48K
Toggle graph series - Users
Users
44
user 100% (empty)
user
100%
(empty)
release 30% 881233
release
30%
881233
environment 90% production
environment
90%
production
activity_id 100% (empty)
activity_id
100%
(empty)
View all tags
View all tags
Select issue content
Events
Previous Event
Next Event
First
First
First
Latest
Latest
Latest
Recommended
Recommended
View More Events
View More Events
Copy as
Copy as
ID: 50b5e01e
8 hours ago
JSON
JSON
Highlights
Highlights
Stack Trace
Stack Trace
Trace
Trace
Tags
Tags
Context...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SevenShores\\Hubspot\\Exceptions\\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your secondly limit.\",\"errorType\":\"RATE_LIMIT","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SevenShores\\Hubspot\\Exceptions\\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your secondly limit.\",\"errorType\":\"RATE_LIMIT","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Service-Desk - Queues - Platform team - Service space - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Service-Desk - Queues - Platform team - Service space - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Illuminate\\Queue\\MaxAttemptsExceededException: Jiminny\\Jobs\\Activity\\DeleteTeamChurnData has been attempted too many times. — jiminny — app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Illuminate\\Queue\\MaxAttemptsExceededException: Jiminny\\Jobs\\Activity\\DeleteTeamChurnData has been attempted too many times. — jiminny — app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Pull requests · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Userpilot | Ask Jiminny Report Generated","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Userpilot | Ask Jiminny Report Generated","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Search the CRM - HubSpot docs","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Search the CRM - HubSpot docs","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.16770834,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"bounds":{"left":0.190625,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"bounds":{"left":0.21388888,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.23715279,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.26041666,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Skip to main content","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip to main content","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle organization menu","depth":11,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Issues","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Issues","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Explore","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Explore","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Dashboards","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Dashboards","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Monitors","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Monitors","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Settings","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Settings","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Try Business","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"What's New","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Help","depth":10,"bounds":{"left":0.34236112,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"lukas.kovalik@jiminny.com","depth":10,"bounds":{"left":0.34236112,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Issues","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Expand","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Feed","depth":15,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Feed","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Errors & Outages","depth":15,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Errors & Outages","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Breached Metrics","depth":15,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Breached Metrics","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Warnings","depth":15,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Warnings","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"User Feedback","depth":15,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"User Feedback","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Autofix","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Autofix","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Recently Run","depth":15,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Recently Run","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"All Views","depth":15,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"All Views","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Configure","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Alerts Moved","depth":15,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Alerts","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Moved","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Issues","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Issues","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"View Project Details","depth":13,"on_screen":true,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"APP-1902","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Ask Seer","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Ask Seer","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Give Feedback","depth":11,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Illuminate\\Queue\\MaxAttemptsExceededException","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"View events","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Events (total)","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"View affected users","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Users (90d)","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Level: Error","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Jiminny\\Jobs\\Activity\\DeleteTeamChurnData has been attempted too many times.","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"260K","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"44","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Ongoing","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/app/Queue/Worker/Worker.php in Jiminny\\Queue\\Worker\\Worker::process","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Resolve","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Resolve","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"More resolve options","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Archive","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Archive","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Archive options","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Subscribe","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Share","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"More Actions","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Priority","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Modify issue priority","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"High","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Assignee","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Modify issue assignee","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Vasil Vasilev","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"All Envs","depth":13,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"All Envs","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"90D","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"90D","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXComboBox","text":"Add a search term","depth":16,"on_screen":true,"help_text":"","placeholder":"Filter events…","role_description":"combo box","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXComboBox","text":"Add a search term","depth":16,"on_screen":true,"help_text":"","placeholder":"Filter events…","role_description":"combo box","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close sidebar","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Toggle graph series - Events","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Events","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"48K","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle graph series - Users","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Users","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"44","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"user 100% (empty)","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"user","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"100%","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(empty)","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"release 30% 881233","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"release","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"30%","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"881233","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"environment 90% production","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"environment","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"90%","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"production","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"activity_id 100% (empty)","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"activity_id","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"100%","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(empty)","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"View all tags","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"View all tags","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Select issue content","depth":13,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Events","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Previous Event","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Next Event","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"First","depth":14,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"First","depth":15,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"First","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Latest","depth":14,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Latest","depth":15,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Latest","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Recommended","depth":14,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Recommended","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"View More Events","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"View More Events","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy as","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Copy as","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ID: 50b5e01e","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"8 hours ago","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JSON","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JSON","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Highlights","depth":17,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Highlights","depth":19,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Stack Trace","depth":17,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Stack Trace","depth":19,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Trace","depth":17,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Trace","depth":19,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Tags","depth":17,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Tags","depth":19,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Context","depth":17,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false}]...
|
1415050720007875504
|
-2428426148993370944
|
visual_change
|
accessibility
|
NULL
|
Platform Sprint 3 Q2 - Platform Team - Scrum Board Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
SevenShores\Hubspot\Exceptions\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your secondly limit.","errorType":"RATE_LIMIT
SevenShores\Hubspot\Exceptions\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your secondly limit.","errorType":"RATE_LIMIT
Service-Desk - Queues - Platform team - Service space - Jira
Service-Desk - Queues - Platform team - Service space - Jira
Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app
Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app
Illuminate\Queue\MaxAttemptsExceededException: Jiminny\Jobs\Activity\DeleteTeamChurnData has been attempted too many times. — jiminny — app
Illuminate\Queue\MaxAttemptsExceededException: Jiminny\Jobs\Activity\DeleteTeamChurnData has been attempted too many times. — jiminny — app
Close tab
Pull requests · jiminny/app
Pull requests · jiminny/app
Userpilot | Ask Jiminny Report Generated
Userpilot | Ask Jiminny Report Generated
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
Jiminny
Jiminny
Search the CRM - HubSpot docs
Search the CRM - HubSpot docs
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Skip to main content
Skip to main content
Toggle organization menu
Issues
Issues
Explore
Explore
Dashboards
Dashboards
Monitors
Monitors
Settings
Settings
Try Business
What's New
Help
[EMAIL]
Issues
Expand
Feed
Feed
Errors & Outages
Errors & Outages
Breached Metrics
Breached Metrics
Warnings
Warnings
User Feedback
User Feedback
Autofix
Autofix
Recently Run
Recently Run
All Views
All Views
Configure
Alerts Moved
Alerts
Moved
Issues
Issues
View Project Details
APP-1902
Ask Seer
Ask Seer
/
Give Feedback
Illuminate\Queue\MaxAttemptsExceededException
View events
Events (total)
View affected users
Users (90d)
Level: Error
Jiminny\Jobs\Activity\DeleteTeamChurnData has been attempted too many times.
260K
44
Ongoing
/app/Queue/Worker/Worker.php in Jiminny\Queue\Worker\Worker::process
Resolve
Resolve
More resolve options
Archive
Archive
Archive options
Subscribe
Share
More Actions
Priority
Modify issue priority
High
Assignee
Modify issue assignee
Vasil Vasilev
All Envs
All Envs
90D
90D
Add a search term
Add a search term
Close sidebar
Toggle graph series - Events
Events
48K
Toggle graph series - Users
Users
44
user 100% (empty)
user
100%
(empty)
release 30% 881233
release
30%
881233
environment 90% production
environment
90%
production
activity_id 100% (empty)
activity_id
100%
(empty)
View all tags
View all tags
Select issue content
Events
Previous Event
Next Event
First
First
First
Latest
Latest
Latest
Recommended
Recommended
View More Events
View More Events
Copy as
Copy as
ID: 50b5e01e
8 hours ago
JSON
JSON
Highlights
Highlights
Stack Trace
Stack Trace
Trace
Trace
Tags
Tags
Context...
|
4974
|
NULL
|
NULL
|
NULL
|
|
5088
|
181
|
43
|
2026-05-07T14:50:43.297096+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-07/1778 /Users/lukas/.screenpipe/data/data/2026-05-07/1778165443297_m1.jpg...
|
Firefox
|
Jiminny — Work
|
True
|
app.staging.jiminny.com/dashboard
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 3 Q2 - Platform Team - Scrum Board Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
SevenShores\Hubspot\Exceptions\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your secondly limit.","errorType":"RATE_LIMIT
SevenShores\Hubspot\Exceptions\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your secondly limit.","errorType":"RATE_LIMIT
Service-Desk - Queues - Platform team - Service space - Jira
Service-Desk - Queues - Platform team - Service space - Jira
Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app
Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app
Illuminate\Queue\MaxAttemptsExceededException: Jiminny\Jobs\Activity\DeleteTeamChurnData has been attempted too many times. — jiminny — app
Illuminate\Queue\MaxAttemptsExceededException: Jiminny\Jobs\Activity\DeleteTeamChurnData has been attempted too many times. — jiminny — app
Pull requests · jiminny/app
Pull requests · jiminny/app
Userpilot | Ask Jiminny Report Generated
Userpilot | Ask Jiminny Report Generated
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
Problem loading page
Problem loading page
Search the CRM - HubSpot docs
Search the CRM - HubSpot docs
Jiminny
Jiminny
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
JY-20733-autoloader-optimization ■ 876223
75
75
My Recordings
My Recordings
Everyone's Recordings
Everyone's Recordings
No Recordings
Schedule
Schedule
Invite Notetaker
This Week
This Week
Everyone's Schedule
Everyone's Schedule
Unknown Customer
Stefka / James Weekly
Tomorrow, 3:15 PM
Trending this month
Trending this month
Sort by Sort by: Most played
Sort by
Sort by:
Most played
Unknown Customer
Notetaker added by Veselin Kulov
Notetaker added by Veselin Kulov
2
times played
Unknown Customer
Notetaker added by Veselin Kulov
Notetaker added by Veselin Kulov
1
times played
Unknown Customer
Notetaker added by Veselin Kulov
Notetaker added by Veselin Kulov
1
times played
Unknown Customer
Processing tickets review
Processing tickets review
0
times played
Unknown Customer
Daily - Processing
Daily - Processing
0
times played
Unknown Customer
Planing - Processing
Planing - Processing
0
times played
Unknown Customer
Daily - Processing
Daily - Processing
0
times played
Unknown Customer
Refinement - Processing
Refinement - Processing
0
times played
Unknown Customer
2026-04-08-call-to-[CREDIT_CARD]-04-08-call-to-441173692222
0
times played
Unknown Customer
Daily - Processing
Daily - Processing
0
times played
Unknown Customer
Daily - Processing
Daily - Processing
0
times played
Unknown Customer
Notetaker added by Todor Stamatov
Notetaker added by Todor Stamatov
0
times played
Unknown Customer
Stefka / James Weekly
Stefka / James Weekly
0
times played
Unknown Customer
Daily - Processing
Daily - Processing
0
times played
Robinson Crusoe Cruises Limited
Sprint Review
Sprint Review
0
times played
Unknown Customer
Discuss the Desktop app design
Discuss the Desktop app design
0
times played
Unknown Customer
Daily - Processing
Daily - Processing
0
times played
Unknown Customer
Daily - Processing
Daily - Processing
0
times played
Unknown Customer
Daily - Processing
Daily - Processing
0
times played
Robinson Crusoe Cruises Limited
Sprint Review
Sprint Review
0
times played
Unknown Customer
Daily - Processing
Daily - Processing
0
times played
Unknown Customer
Refinement - Processing
Refinement - Processing
0
times played
Unknown Customer
Notetaker added by Mihail Mihaylov
Notetaker added by Mihail Mihaylov
0
times played
Unknown Customer
Planing - Processing
Planing - Processing
0
times played
Unknown Customer
Kara / James
Kara / James
0
times played
Live Feed
Live Feed
Veselin Kulov
listened to call
Today, 3:47 PM
activity
with
unknown customer
Held:
Today, 10:37 AM
Duration:
4m
Value:
$0
Veselin Kulov
listened to call
Today, 11:12 AM
activity
with
unknown customer
Held:
Today, 10:37 AM
Duration:
4m
Value:
$0
Veselin Kulov
listened to call
29 Apr, 2:03 PM
activity
with
unknown customer
Held:
29 Apr, 1:33 PM
Duration:
4m
Value:
$0
Veselin Kulov
listened to call
8 Apr, 12:51 AM
activity
with
unknown customer...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SevenShores\\Hubspot\\Exceptions\\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your secondly limit.\",\"errorType\":\"RATE_LIMIT","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SevenShores\\Hubspot\\Exceptions\\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your secondly limit.\",\"errorType\":\"RATE_LIMIT","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Service-Desk - Queues - Platform team - Service space - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Service-Desk - Queues - Platform team - Service space - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Illuminate\\Queue\\MaxAttemptsExceededException: Jiminny\\Jobs\\Activity\\DeleteTeamChurnData has been attempted too many times. — jiminny — app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Illuminate\\Queue\\MaxAttemptsExceededException: Jiminny\\Jobs\\Activity\\DeleteTeamChurnData has been attempted too many times. — jiminny — app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Pull requests · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Userpilot | Ask Jiminny Report Generated","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Userpilot | Ask Jiminny Report Generated","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Problem loading page","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Problem loading page","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Search the CRM - HubSpot docs","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Search the CRM - HubSpot docs","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Jiminny","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.16770834,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"bounds":{"left":0.190625,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"bounds":{"left":0.21388888,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.23715279,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.26041666,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20733-autoloader-optimization ■ 876223","depth":9,"bounds":{"left":0.32951388,"top":0.0,"width":0.18194444,"height":0.017777778},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"75","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"75","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"My Recordings","depth":14,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"My Recordings","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Everyone's Recordings","depth":14,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Everyone's Recordings","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"No Recordings","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Schedule","depth":13,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Schedule","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Invite Notetaker","depth":14,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXComboBox","text":"This Week","depth":14,"on_screen":true,"value":"This Week","help_text":"","role_description":"combo box","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"This Week","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXComboBox","text":"Everyone's Schedule","depth":14,"on_screen":true,"value":"Everyone's Schedule","help_text":"","role_description":"combo box","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Everyone's Schedule","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Unknown Customer","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Stefka / James Weekly","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Tomorrow, 3:15 PM","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Trending this month","depth":13,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Trending this month","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXComboBox","text":"Sort by Sort by: Most played","depth":13,"on_screen":true,"value":"Sort by Sort by: Most played","help_text":"","role_description":"combo box","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"Sort by","depth":14,"on_screen":false,"help_text":"","role_description":"text field","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sort by:","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Most played","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Unknown Customer","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Notetaker added by Veselin Kulov","depth":15,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Notetaker added by Veselin Kulov","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"times played","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Unknown Customer","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Notetaker added by Veselin Kulov","depth":15,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Notetaker added by Veselin Kulov","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"times played","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Unknown Customer","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Notetaker added by Veselin Kulov","depth":15,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Notetaker added by Veselin Kulov","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"times played","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Unknown Customer","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Processing tickets review","depth":15,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Processing tickets review","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"times played","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Unknown Customer","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Daily - Processing","depth":15,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Daily - Processing","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"times played","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Unknown Customer","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Planing - Processing","depth":15,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Planing - Processing","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"times played","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Unknown Customer","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Daily - Processing","depth":15,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Daily - Processing","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"times played","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Unknown Customer","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Refinement - Processing","depth":15,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Refinement - Processing","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"times played","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Unknown Customer","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"2026-04-08-call-to-441173692222","depth":15,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"2026-04-08-call-to-441173692222","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"times played","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Unknown Customer","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Daily - Processing","depth":15,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Daily - Processing","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"times played","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Unknown Customer","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Daily - Processing","depth":15,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Daily - Processing","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"times played","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Unknown Customer","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Notetaker added by Todor Stamatov","depth":15,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Notetaker added by Todor Stamatov","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"times played","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Unknown Customer","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Stefka / James Weekly","depth":15,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Stefka / James Weekly","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"times played","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Unknown Customer","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Daily - Processing","depth":15,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Daily - Processing","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"times played","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Robinson Crusoe Cruises Limited","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Sprint Review","depth":15,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sprint Review","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"times played","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Unknown Customer","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Discuss the Desktop app design","depth":15,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Discuss the Desktop app design","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"times played","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Unknown Customer","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Daily - Processing","depth":15,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Daily - Processing","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"times played","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Unknown Customer","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Daily - Processing","depth":15,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Daily - Processing","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"times played","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Unknown Customer","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Daily - Processing","depth":15,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Daily - Processing","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"times played","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Robinson Crusoe Cruises Limited","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Sprint Review","depth":15,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sprint Review","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"times played","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Unknown Customer","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Daily - Processing","depth":15,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Daily - Processing","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"times played","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Unknown Customer","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Refinement - Processing","depth":15,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Refinement - Processing","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"times played","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Unknown Customer","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Notetaker added by Mihail Mihaylov","depth":15,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Notetaker added by Mihail Mihaylov","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"times played","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Unknown Customer","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Planing - Processing","depth":15,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Planing - Processing","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"times played","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Unknown Customer","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Kara / James","depth":15,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Kara / James","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"times played","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Live Feed","depth":13,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Live Feed","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Veselin Kulov","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"listened to call","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Today, 3:47 PM","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"activity","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"with","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"unknown customer","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Held:","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Today, 10:37 AM","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Duration:","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"4m","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Value:","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$0","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Veselin Kulov","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"listened to call","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Today, 11:12 AM","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"activity","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"with","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"unknown customer","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Held:","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Today, 10:37 AM","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Duration:","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"4m","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Value:","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$0","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Veselin Kulov","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"listened to call","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"29 Apr, 2:03 PM","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"activity","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"with","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"unknown customer","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Held:","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"29 Apr, 1:33 PM","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Duration:","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"4m","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Value:","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$0","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Veselin Kulov","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"listened to call","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"8 Apr, 12:51 AM","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"activity","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"with","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"unknown customer","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
7513218974560274468
|
1895605650324548488
|
visual_change
|
accessibility
|
NULL
|
Platform Sprint 3 Q2 - Platform Team - Scrum Board Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
SevenShores\Hubspot\Exceptions\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your secondly limit.","errorType":"RATE_LIMIT
SevenShores\Hubspot\Exceptions\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your secondly limit.","errorType":"RATE_LIMIT
Service-Desk - Queues - Platform team - Service space - Jira
Service-Desk - Queues - Platform team - Service space - Jira
Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app
Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app
Illuminate\Queue\MaxAttemptsExceededException: Jiminny\Jobs\Activity\DeleteTeamChurnData has been attempted too many times. — jiminny — app
Illuminate\Queue\MaxAttemptsExceededException: Jiminny\Jobs\Activity\DeleteTeamChurnData has been attempted too many times. — jiminny — app
Pull requests · jiminny/app
Pull requests · jiminny/app
Userpilot | Ask Jiminny Report Generated
Userpilot | Ask Jiminny Report Generated
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
Problem loading page
Problem loading page
Search the CRM - HubSpot docs
Search the CRM - HubSpot docs
Jiminny
Jiminny
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
JY-20733-autoloader-optimization ■ 876223
75
75
My Recordings
My Recordings
Everyone's Recordings
Everyone's Recordings
No Recordings
Schedule
Schedule
Invite Notetaker
This Week
This Week
Everyone's Schedule
Everyone's Schedule
Unknown Customer
Stefka / James Weekly
Tomorrow, 3:15 PM
Trending this month
Trending this month
Sort by Sort by: Most played
Sort by
Sort by:
Most played
Unknown Customer
Notetaker added by Veselin Kulov
Notetaker added by Veselin Kulov
2
times played
Unknown Customer
Notetaker added by Veselin Kulov
Notetaker added by Veselin Kulov
1
times played
Unknown Customer
Notetaker added by Veselin Kulov
Notetaker added by Veselin Kulov
1
times played
Unknown Customer
Processing tickets review
Processing tickets review
0
times played
Unknown Customer
Daily - Processing
Daily - Processing
0
times played
Unknown Customer
Planing - Processing
Planing - Processing
0
times played
Unknown Customer
Daily - Processing
Daily - Processing
0
times played
Unknown Customer
Refinement - Processing
Refinement - Processing
0
times played
Unknown Customer
2026-04-08-call-to-[CREDIT_CARD]-04-08-call-to-441173692222
0
times played
Unknown Customer
Daily - Processing
Daily - Processing
0
times played
Unknown Customer
Daily - Processing
Daily - Processing
0
times played
Unknown Customer
Notetaker added by Todor Stamatov
Notetaker added by Todor Stamatov
0
times played
Unknown Customer
Stefka / James Weekly
Stefka / James Weekly
0
times played
Unknown Customer
Daily - Processing
Daily - Processing
0
times played
Robinson Crusoe Cruises Limited
Sprint Review
Sprint Review
0
times played
Unknown Customer
Discuss the Desktop app design
Discuss the Desktop app design
0
times played
Unknown Customer
Daily - Processing
Daily - Processing
0
times played
Unknown Customer
Daily - Processing
Daily - Processing
0
times played
Unknown Customer
Daily - Processing
Daily - Processing
0
times played
Robinson Crusoe Cruises Limited
Sprint Review
Sprint Review
0
times played
Unknown Customer
Daily - Processing
Daily - Processing
0
times played
Unknown Customer
Refinement - Processing
Refinement - Processing
0
times played
Unknown Customer
Notetaker added by Mihail Mihaylov
Notetaker added by Mihail Mihaylov
0
times played
Unknown Customer
Planing - Processing
Planing - Processing
0
times played
Unknown Customer
Kara / James
Kara / James
0
times played
Live Feed
Live Feed
Veselin Kulov
listened to call
Today, 3:47 PM
activity
with
unknown customer
Held:
Today, 10:37 AM
Duration:
4m
Value:
$0
Veselin Kulov
listened to call
Today, 11:12 AM
activity
with
unknown customer
Held:
Today, 10:37 AM
Duration:
4m
Value:
$0
Veselin Kulov
listened to call
29 Apr, 2:03 PM
activity
with
unknown customer
Held:
29 Apr, 1:33 PM
Duration:
4m
Value:
$0
Veselin Kulov
listened to call
8 Apr, 12:51 AM
activity
with
unknown customer...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
5180
|
183
|
43
|
2026-05-07T14:56:50.277098+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-07/1778 /Users/lukas/.screenpipe/data/data/2026-05-07/1778165810277_m1.jpg...
|
Firefox
|
Platform Sprint 3 Q2 - Platform Team - Scrum Board Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira — Work...
|
True
|
jiminny.atlassian.net/jira/software/c/projects/JY/ jiminny.atlassian.net/jira/software/c/projects/JY/boards/37...
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 3 Q2 - Platform Team - Scrum Board Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Close tab
SevenShores\Hubspot\Exceptions\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your secondly limit.","errorType":"RATE_LIMIT
SevenShores\Hubspot\Exceptions\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your secondly limit.","errorType":"RATE_LIMIT
Service-Desk - Queues - Platform team - Service space - Jira
Service-Desk - Queues - Platform team - Service space - Jira
Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app
Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app
Illuminate\Queue\MaxAttemptsExceededException: Jiminny\Jobs\Activity\DeleteTeamChurnData has been attempted too many times. — jiminny — app
Illuminate\Queue\MaxAttemptsExceededException: Jiminny\Jobs\Activity\DeleteTeamChurnData has been attempted too many times. — jiminny — app
Pull requests · jiminny/app
Pull requests · jiminny/app
Userpilot | Ask Jiminny Report Generated
Userpilot | Ask Jiminny Report Generated
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
Problem loading page
Problem loading page
Search the CRM - HubSpot docs
Search the CRM - HubSpot docs
Jiminny
Jiminny
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Skip to:
Top Bar
Top Bar
Sidebar
Sidebar
Main Content
Main Content
Space navigation
Space navigation
Collapse sidebar [
Collapse sidebar [
Switch sites or apps
Switch sites or apps
Go to your Jira homepage
Search, press enter to navigate to advanced search with your text query
Create
Create
Rovo Ask Rovo
Ask Rovo
Notifications
Notifications
Help
Help
Settings
Settings
[EMAIL]
[EMAIL]
For you
For you
Recent
Recent
Starred
Starred
Apps
Apps
More actions for Apps
More actions for Apps
Spaces
Spaces
Create space
Create space
More actions for spaces
More actions for spaces
Recent
Jiminny (New)
Jiminny (New)
Jiminny (New)
Create board
Create board
More actions for Jiminny (New)
More actions for Jiminny (New)
Platform Team
Platform Team
Board actions
Board actions
Capture Team
Capture Team
Board actions
Board actions
Enterprise Stability Issues 🤕
Enterprise Stability Issues 🤕
Board actions
Board actions
Processing Team
Processing Team
Board actions
Board actions
SE Kanban
SE Kanban
Board actions
Board actions
Service-Desk
Service-Desk
More actions for Service-Desk
More actions for Service-Desk
More spaces
More spaces
Filters
Filters
More actions for Filters
More actions for Filters
Dashboards
Dashboards
Create dashboard
Create dashboard
More actions for Dashboards
More actions for Dashboards
Operations
Operations
More actions for Operations
More actions for Operations
Confluence , (opens new window)
Confluence
, (opens new window)
Teams , (opens new window)
Teams
, (opens new window)
open menu
open menu
Customise sidebar
Customise sidebar
Resize side navigation panel
Spaces
Spaces
/
Jiminny (New)
Jiminny (New)
Platform Team
Platform Team
Add people
Add people
Board actions
Board actions
Share
Automation
Give feedback
Give feedback
Enter full screen
Enter full screen
Summary
Summary
Timeline
Timeline
Backlog
Backlog
Active sprints
Active sprints
Calendar
Calendar
Reports
Reports
Testing Board
Testing Board
List
List
Forms
Forms
Components
Components
Development
Development
Code
Code
8 more tabs...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"SevenShores\\Hubspot\\Exceptions\\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your secondly limit.\",\"errorType\":\"RATE_LIMIT","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SevenShores\\Hubspot\\Exceptions\\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your secondly limit.\",\"errorType\":\"RATE_LIMIT","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Service-Desk - Queues - Platform team - Service space - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Service-Desk - Queues - Platform team - Service space - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Illuminate\\Queue\\MaxAttemptsExceededException: Jiminny\\Jobs\\Activity\\DeleteTeamChurnData has been attempted too many times. — jiminny — app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Illuminate\\Queue\\MaxAttemptsExceededException: Jiminny\\Jobs\\Activity\\DeleteTeamChurnData has been attempted too many times. — jiminny — app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Pull requests · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Userpilot | Ask Jiminny Report Generated","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Userpilot | Ask Jiminny Report Generated","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Problem loading page","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Problem loading page","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Search the CRM - HubSpot docs","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Search the CRM - HubSpot docs","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.16770834,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"bounds":{"left":0.190625,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"bounds":{"left":0.21388888,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.23715279,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.26041666,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip to:","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Top Bar","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Top Bar","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Sidebar","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sidebar","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Main Content","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Main Content","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Space navigation","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Space navigation","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Collapse sidebar [","depth":9,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Collapse sidebar [","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Switch sites or apps","depth":10,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Switch sites or apps","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Go to your Jira homepage","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXComboBox","text":"Search, press enter to navigate to advanced search with your text query","depth":11,"on_screen":true,"help_text":"","placeholder":"Search","role_description":"combo box","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Create","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Create","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Rovo Ask Rovo","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Ask Rovo","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Notifications","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Notifications","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Help","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Help","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Settings","depth":12,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Settings","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"lukas.kovalik@jiminny.com","depth":12,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"lukas.kovalik@jiminny.com","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"For you","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"For you","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Recent","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Recent","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Starred","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Starred","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Apps","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Apps","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Apps","depth":13,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More actions for Apps","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Spaces","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXStaticText","text":"Spaces","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Create space","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Create space","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for spaces","depth":13,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More actions for spaces","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Recent","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Jiminny (New)","depth":17,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny (New)","depth":20,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Jiminny (New)","depth":18,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXMenuButton","text":"Create board","depth":18,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Create board","depth":20,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Jiminny (New)","depth":18,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More actions for Jiminny (New)","depth":20,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Platform Team","depth":19,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":true,"is_selected":false},{"role":"AXStaticText","text":"Platform Team","depth":22,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":20,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Board actions","depth":22,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Capture Team","depth":19,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Capture Team","depth":22,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":20,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Board actions","depth":22,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Enterprise Stability Issues 🤕","depth":19,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Enterprise Stability Issues 🤕","depth":22,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":20,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Board actions","depth":22,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Processing Team","depth":19,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Processing Team","depth":22,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":20,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Board actions","depth":22,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SE Kanban","depth":19,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SE Kanban","depth":22,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":20,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Board actions","depth":22,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Service-Desk","depth":17,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Service-Desk","depth":20,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Service-Desk","depth":18,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More actions for Service-Desk","depth":20,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"More spaces","depth":17,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More spaces","depth":20,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Filters","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Filters","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Filters","depth":13,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More actions for Filters","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Dashboards","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Dashboards","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Create dashboard","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Create dashboard","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Dashboards","depth":13,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More actions for Dashboards","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Operations","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Operations","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Operations","depth":13,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More actions for Operations","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Confluence , (opens new window)","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Confluence","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", (opens new window)","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Teams , (opens new window)","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Teams","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", (opens new window)","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"open menu","depth":14,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"open menu","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Customise sidebar","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Customise sidebar","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Resize side navigation panel","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Spaces","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Spaces","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Jiminny (New)","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny (New)","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Platform Team","depth":10,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Platform Team","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Add people","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Add people","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":10,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Board actions","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Share","depth":10,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXMenuButton","text":"Automation","depth":10,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Give feedback","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Give feedback","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Enter full screen","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Enter full screen","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Summary","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Summary","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Timeline","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Timeline","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Backlog","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Backlog","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Active sprints","depth":13,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Active sprints","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Calendar","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Calendar","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Reports","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Reports","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Testing Board","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Testing Board","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"List","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"List","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Forms","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Forms","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Components","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Components","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Development","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Development","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Code","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Code","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"8 more tabs","depth":11,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
3233412256714407557
|
6293022969920999424
|
visual_change
|
accessibility
|
NULL
|
Platform Sprint 3 Q2 - Platform Team - Scrum Board Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Close tab
SevenShores\Hubspot\Exceptions\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your secondly limit.","errorType":"RATE_LIMIT
SevenShores\Hubspot\Exceptions\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your secondly limit.","errorType":"RATE_LIMIT
Service-Desk - Queues - Platform team - Service space - Jira
Service-Desk - Queues - Platform team - Service space - Jira
Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app
Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app
Illuminate\Queue\MaxAttemptsExceededException: Jiminny\Jobs\Activity\DeleteTeamChurnData has been attempted too many times. — jiminny — app
Illuminate\Queue\MaxAttemptsExceededException: Jiminny\Jobs\Activity\DeleteTeamChurnData has been attempted too many times. — jiminny — app
Pull requests · jiminny/app
Pull requests · jiminny/app
Userpilot | Ask Jiminny Report Generated
Userpilot | Ask Jiminny Report Generated
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
Problem loading page
Problem loading page
Search the CRM - HubSpot docs
Search the CRM - HubSpot docs
Jiminny
Jiminny
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Skip to:
Top Bar
Top Bar
Sidebar
Sidebar
Main Content
Main Content
Space navigation
Space navigation
Collapse sidebar [
Collapse sidebar [
Switch sites or apps
Switch sites or apps
Go to your Jira homepage
Search, press enter to navigate to advanced search with your text query
Create
Create
Rovo Ask Rovo
Ask Rovo
Notifications
Notifications
Help
Help
Settings
Settings
[EMAIL]
[EMAIL]
For you
For you
Recent
Recent
Starred
Starred
Apps
Apps
More actions for Apps
More actions for Apps
Spaces
Spaces
Create space
Create space
More actions for spaces
More actions for spaces
Recent
Jiminny (New)
Jiminny (New)
Jiminny (New)
Create board
Create board
More actions for Jiminny (New)
More actions for Jiminny (New)
Platform Team
Platform Team
Board actions
Board actions
Capture Team
Capture Team
Board actions
Board actions
Enterprise Stability Issues 🤕
Enterprise Stability Issues 🤕
Board actions
Board actions
Processing Team
Processing Team
Board actions
Board actions
SE Kanban
SE Kanban
Board actions
Board actions
Service-Desk
Service-Desk
More actions for Service-Desk
More actions for Service-Desk
More spaces
More spaces
Filters
Filters
More actions for Filters
More actions for Filters
Dashboards
Dashboards
Create dashboard
Create dashboard
More actions for Dashboards
More actions for Dashboards
Operations
Operations
More actions for Operations
More actions for Operations
Confluence , (opens new window)
Confluence
, (opens new window)
Teams , (opens new window)
Teams
, (opens new window)
open menu
open menu
Customise sidebar
Customise sidebar
Resize side navigation panel
Spaces
Spaces
/
Jiminny (New)
Jiminny (New)
Platform Team
Platform Team
Add people
Add people
Board actions
Board actions
Share
Automation
Give feedback
Give feedback
Enter full screen
Enter full screen
Summary
Summary
Timeline
Timeline
Backlog
Backlog
Active sprints
Active sprints
Calendar
Calendar
Reports
Reports
Testing Board
Testing Board
List
List
Forms
Forms
Components
Components
Development
Development
Code
Code
8 more tabs...
|
5179
|
NULL
|
NULL
|
NULL
|
|
5249
|
185
|
43
|
2026-05-07T15:02:54.011114+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-07/1778 /Users/lukas/.screenpipe/data/data/2026-05-07/1778166174011_m1.jpg...
|
Firefox
|
Platform Sprint 3 Q2 - Platform Team - Scrum Board Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira — Work...
|
True
|
jiminny.atlassian.net/jira/software/c/projects/JY/ jiminny.atlassian.net/jira/software/c/projects/JY/boards/37...
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 3 Q2 - Platform Team - Scrum Board Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Close tab
SevenShores\Hubspot\Exceptions\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your secondly limit.","errorType":"RATE_LIMIT
SevenShores\Hubspot\Exceptions\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your secondly limit.","errorType":"RATE_LIMIT
Service-Desk - Queues - Platform team - Service space - Jira
Service-Desk - Queues - Platform team - Service space - Jira
Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app
Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app
Illuminate\Queue\MaxAttemptsExceededException: Jiminny\Jobs\Activity\DeleteTeamChurnData has been attempted too many times. — jiminny — app
Illuminate\Queue\MaxAttemptsExceededException: Jiminny\Jobs\Activity\DeleteTeamChurnData has been attempted too many times. — jiminny — app
Pull requests · jiminny/app
Pull requests · jiminny/app
Userpilot | Ask Jiminny Report Generated
Userpilot | Ask Jiminny Report Generated
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
Problem loading page
Problem loading page
Search the CRM - HubSpot docs
Search the CRM - HubSpot docs
Jiminny
Jiminny
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Skip to:
Top Bar
Top Bar
Sidebar
Sidebar
Main Content
Main Content
Space navigation
Space navigation
Collapse sidebar [
Collapse sidebar [
Switch sites or apps
Switch sites or apps
Go to your Jira homepage
Search, press enter to navigate to advanced search with your text query
Create
Create
Rovo Ask Rovo
Ask Rovo
Notifications
Notifications
Help
Help
Settings
Settings
[EMAIL]
[EMAIL]
For you
For you
Recent
Recent
Starred
Starred
Apps
Apps
More actions for Apps
More actions for Apps
Spaces
Spaces
Create space
Create space
More actions for spaces
More actions for spaces
Recent
Jiminny (New)
Jiminny (New)
Jiminny (New)
Create board
Create board
More actions for Jiminny (New)
More actions for Jiminny (New)
Platform Team
Platform Team
Board actions
Board actions
Capture Team
Capture Team
Board actions
Board actions
Enterprise Stability Issues 🤕
Enterprise Stability Issues 🤕
Board actions
Board actions
Processing Team
Processing Team
Board actions
Board actions
SE Kanban
SE Kanban
Board actions
Board actions
Service-Desk
Service-Desk
More actions for Service-Desk
More actions for Service-Desk
More spaces
More spaces
Filters
Filters
More actions for Filters
More actions for Filters
Dashboards
Dashboards
Create dashboard
Create dashboard
More actions for Dashboards
More actions for Dashboards
Operations
Operations
More actions for Operations
More actions for Operations
Confluence , (opens new window)
Confluence
, (opens new window)
Teams , (opens new window)
Teams
, (opens new window)
open menu
open menu
Customise sidebar
Customise sidebar
Resize side navigation panel
Spaces
Spaces
/
Jiminny (New)
Jiminny (New)
Platform Team
Platform Team
Add people
Add people
Board actions
Board actions
Share
Automation
Give feedback
Give feedback
Enter full screen
Enter full screen
Summary
Summary
Timeline
Timeline
Backlog
Backlog
Active sprints
Active sprints
Calendar
Calendar
Reports
Reports
Testing Board
Testing Board
List
List
Forms
Forms
Components
Components
Development
Development
Code
Code
8 more tabs
More
8
Add to navigation
As you type to search or apply filters, the board updates with work items to match.
Search on current page
Filter by assignee
Filter assignees by Lukas Kovalik
Filter assignees by Aneliya Angelova
Filter assignees by Nikolay Ivanov
Filter assignees by Nikolay Nikolov
Filter assignees by Steliyan Georgiev
Filter assignees by Unassigned
Epic
Epic
Type
Type
Quick filters
Quick filters
Complete sprint
Complete sprint
Sprint details...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"SevenShores\\Hubspot\\Exceptions\\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your secondly limit.\",\"errorType\":\"RATE_LIMIT","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SevenShores\\Hubspot\\Exceptions\\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your secondly limit.\",\"errorType\":\"RATE_LIMIT","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Service-Desk - Queues - Platform team - Service space - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Service-Desk - Queues - Platform team - Service space - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Illuminate\\Queue\\MaxAttemptsExceededException: Jiminny\\Jobs\\Activity\\DeleteTeamChurnData has been attempted too many times. — jiminny — app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Illuminate\\Queue\\MaxAttemptsExceededException: Jiminny\\Jobs\\Activity\\DeleteTeamChurnData has been attempted too many times. — jiminny — app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Pull requests · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Userpilot | Ask Jiminny Report Generated","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Userpilot | Ask Jiminny Report Generated","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Problem loading page","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Problem loading page","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Search the CRM - HubSpot docs","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Search the CRM - HubSpot docs","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.16770834,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"bounds":{"left":0.190625,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"bounds":{"left":0.21388888,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.23715279,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.26041666,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip to:","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Top Bar","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Top Bar","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Sidebar","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sidebar","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Main Content","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Main Content","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Space navigation","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Space navigation","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Collapse sidebar [","depth":9,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Collapse sidebar [","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Switch sites or apps","depth":10,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Switch sites or apps","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Go to your Jira homepage","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXComboBox","text":"Search, press enter to navigate to advanced search with your text query","depth":11,"on_screen":true,"help_text":"","placeholder":"Search","role_description":"combo box","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Create","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Create","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Rovo Ask Rovo","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Ask Rovo","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Notifications","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Notifications","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Help","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Help","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Settings","depth":12,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Settings","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"lukas.kovalik@jiminny.com","depth":12,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"lukas.kovalik@jiminny.com","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"For you","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"For you","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Recent","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Recent","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Starred","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Starred","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Apps","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Apps","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Apps","depth":13,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More actions for Apps","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Spaces","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXStaticText","text":"Spaces","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Create space","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Create space","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for spaces","depth":13,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More actions for spaces","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Recent","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Jiminny (New)","depth":17,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny (New)","depth":20,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Jiminny (New)","depth":18,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXMenuButton","text":"Create board","depth":18,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Create board","depth":20,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Jiminny (New)","depth":18,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More actions for Jiminny (New)","depth":20,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Platform Team","depth":19,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":true,"is_selected":false},{"role":"AXStaticText","text":"Platform Team","depth":22,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":20,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Board actions","depth":22,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Capture Team","depth":19,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Capture Team","depth":22,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":20,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Board actions","depth":22,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Enterprise Stability Issues 🤕","depth":19,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Enterprise Stability Issues 🤕","depth":22,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":20,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Board actions","depth":22,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Processing Team","depth":19,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Processing Team","depth":22,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":20,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Board actions","depth":22,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SE Kanban","depth":19,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SE Kanban","depth":22,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":20,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Board actions","depth":22,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Service-Desk","depth":17,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Service-Desk","depth":20,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Service-Desk","depth":18,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More actions for Service-Desk","depth":20,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"More spaces","depth":17,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More spaces","depth":20,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Filters","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Filters","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Filters","depth":13,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More actions for Filters","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Dashboards","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Dashboards","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Create dashboard","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Create dashboard","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Dashboards","depth":13,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More actions for Dashboards","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Operations","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Operations","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Operations","depth":13,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More actions for Operations","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Confluence , (opens new window)","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Confluence","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", (opens new window)","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Teams , (opens new window)","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Teams","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", (opens new window)","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"open menu","depth":14,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"open menu","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Customise sidebar","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Customise sidebar","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Resize side navigation panel","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Spaces","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Spaces","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Jiminny (New)","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny (New)","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Platform Team","depth":10,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Platform Team","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Add people","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Add people","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":10,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Board actions","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Share","depth":10,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXMenuButton","text":"Automation","depth":10,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Give feedback","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Give feedback","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Enter full screen","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Enter full screen","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Summary","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Summary","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Timeline","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Timeline","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Backlog","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Backlog","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Active sprints","depth":13,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Active sprints","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Calendar","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Calendar","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Reports","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Reports","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Testing Board","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Testing Board","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"List","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"List","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Forms","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Forms","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Components","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Components","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Development","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Development","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Code","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Code","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"8 more tabs","depth":11,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"8","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Add to navigation","depth":11,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"As you type to search or apply filters, the board updates with work items to match.","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXTextField","text":"Search on current page","depth":11,"on_screen":true,"placeholder":"Search board","role_description":"text field","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Filter by assignee","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Filter assignees by Lukas Kovalik","depth":11,"on_screen":true,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Filter assignees by Aneliya Angelova","depth":11,"on_screen":true,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Filter assignees by Nikolay Ivanov","depth":11,"on_screen":true,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Filter assignees by Nikolay Nikolov","depth":11,"on_screen":true,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Filter assignees by Steliyan Georgiev","depth":11,"on_screen":true,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Filter assignees by Unassigned","depth":11,"on_screen":true,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Epic","depth":13,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Epic","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Type","depth":13,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Type","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Quick filters","depth":13,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Quick filters","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Complete sprint","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Complete sprint","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Sprint details","depth":10,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-8437989793774474053
|
5932770308657370120
|
visual_change
|
accessibility
|
NULL
|
Platform Sprint 3 Q2 - Platform Team - Scrum Board Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Close tab
SevenShores\Hubspot\Exceptions\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your secondly limit.","errorType":"RATE_LIMIT
SevenShores\Hubspot\Exceptions\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your secondly limit.","errorType":"RATE_LIMIT
Service-Desk - Queues - Platform team - Service space - Jira
Service-Desk - Queues - Platform team - Service space - Jira
Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app
Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app
Illuminate\Queue\MaxAttemptsExceededException: Jiminny\Jobs\Activity\DeleteTeamChurnData has been attempted too many times. — jiminny — app
Illuminate\Queue\MaxAttemptsExceededException: Jiminny\Jobs\Activity\DeleteTeamChurnData has been attempted too many times. — jiminny — app
Pull requests · jiminny/app
Pull requests · jiminny/app
Userpilot | Ask Jiminny Report Generated
Userpilot | Ask Jiminny Report Generated
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
Problem loading page
Problem loading page
Search the CRM - HubSpot docs
Search the CRM - HubSpot docs
Jiminny
Jiminny
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Skip to:
Top Bar
Top Bar
Sidebar
Sidebar
Main Content
Main Content
Space navigation
Space navigation
Collapse sidebar [
Collapse sidebar [
Switch sites or apps
Switch sites or apps
Go to your Jira homepage
Search, press enter to navigate to advanced search with your text query
Create
Create
Rovo Ask Rovo
Ask Rovo
Notifications
Notifications
Help
Help
Settings
Settings
[EMAIL]
[EMAIL]
For you
For you
Recent
Recent
Starred
Starred
Apps
Apps
More actions for Apps
More actions for Apps
Spaces
Spaces
Create space
Create space
More actions for spaces
More actions for spaces
Recent
Jiminny (New)
Jiminny (New)
Jiminny (New)
Create board
Create board
More actions for Jiminny (New)
More actions for Jiminny (New)
Platform Team
Platform Team
Board actions
Board actions
Capture Team
Capture Team
Board actions
Board actions
Enterprise Stability Issues 🤕
Enterprise Stability Issues 🤕
Board actions
Board actions
Processing Team
Processing Team
Board actions
Board actions
SE Kanban
SE Kanban
Board actions
Board actions
Service-Desk
Service-Desk
More actions for Service-Desk
More actions for Service-Desk
More spaces
More spaces
Filters
Filters
More actions for Filters
More actions for Filters
Dashboards
Dashboards
Create dashboard
Create dashboard
More actions for Dashboards
More actions for Dashboards
Operations
Operations
More actions for Operations
More actions for Operations
Confluence , (opens new window)
Confluence
, (opens new window)
Teams , (opens new window)
Teams
, (opens new window)
open menu
open menu
Customise sidebar
Customise sidebar
Resize side navigation panel
Spaces
Spaces
/
Jiminny (New)
Jiminny (New)
Platform Team
Platform Team
Add people
Add people
Board actions
Board actions
Share
Automation
Give feedback
Give feedback
Enter full screen
Enter full screen
Summary
Summary
Timeline
Timeline
Backlog
Backlog
Active sprints
Active sprints
Calendar
Calendar
Reports
Reports
Testing Board
Testing Board
List
List
Forms
Forms
Components
Components
Development
Development
Code
Code
8 more tabs
More
8
Add to navigation
As you type to search or apply filters, the board updates with work items to match.
Search on current page
Filter by assignee
Filter assignees by Lukas Kovalik
Filter assignees by Aneliya Angelova
Filter assignees by Nikolay Ivanov
Filter assignees by Nikolay Nikolov
Filter assignees by Steliyan Georgiev
Filter assignees by Unassigned
Epic
Epic
Type
Type
Quick filters
Quick filters
Complete sprint
Complete sprint
Sprint details...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
5304
|
187
|
43
|
2026-05-07T15:07:57.317869+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-07/1778 /Users/lukas/.screenpipe/data/data/2026-05-07/1778166477317_m1.jpg...
|
Firefox
|
Platform Sprint 3 Q2 - Platform Team - Scrum Board Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira — Work...
|
True
|
jiminny.atlassian.net/jira/software/c/projects/JY/ jiminny.atlassian.net/jira/software/c/projects/JY/boards/37...
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 3 Q2 - Platform Team - Scrum Board Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Close tab
SevenShores\Hubspot\Exceptions\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your secondly limit.","errorType":"RATE_LIMIT
SevenShores\Hubspot\Exceptions\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your secondly limit.","errorType":"RATE_LIMIT
Service-Desk - Queues - Platform team - Service space - Jira
Service-Desk - Queues - Platform team - Service space - Jira
Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app
Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app
Illuminate\Queue\MaxAttemptsExceededException: Jiminny\Jobs\Activity\DeleteTeamChurnData has been attempted too many times. — jiminny — app
Illuminate\Queue\MaxAttemptsExceededException: Jiminny\Jobs\Activity\DeleteTeamChurnData has been attempted too many times. — jiminny — app
Pull requests · jiminny/app
Pull requests · jiminny/app
Userpilot | Ask Jiminny Report Generated
Userpilot | Ask Jiminny Report Generated
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
Problem loading page
Problem loading page
Search the CRM - HubSpot docs
Search the CRM - HubSpot docs
Jiminny
Jiminny
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Skip to:
Top Bar
Top Bar
Sidebar
Sidebar
Main Content
Main Content
Space navigation
Space navigation
Collapse sidebar [
Collapse sidebar [
Switch sites or apps
Switch sites or apps
Go to your Jira homepage
Search, press enter to navigate to advanced search with your text query
Create
Create
Rovo Ask Rovo
Ask Rovo
Notifications
Notifications
Help
Help
Settings
Settings
[EMAIL]
[EMAIL]
For you
For you
Recent
Recent
Starred
Starred
Apps
Apps
More actions for Apps
More actions for Apps
Spaces
Spaces
Create space
Create space
More actions for spaces
More actions for spaces
Recent
Jiminny (New)
Jiminny (New)
Jiminny (New)
Create board
Create board
More actions for Jiminny (New)
More actions for Jiminny (New)
Platform Team
Platform Team
Board actions
Board actions
Capture Team
Capture Team
Board actions
Board actions
Enterprise Stability Issues 🤕
Enterprise Stability Issues 🤕
Board actions
Board actions
Processing Team
Processing Team
Board actions
Board actions
SE Kanban
SE Kanban
Board actions
Board actions
Service-Desk
Service-Desk
More actions for Service-Desk
More actions for Service-Desk
More spaces
More spaces
Filters
Filters
More actions for Filters
More actions for Filters
Dashboards
Dashboards
Create dashboard
Create dashboard
More actions for Dashboards
More actions for Dashboards
Operations
Operations
More actions for Operations
More actions for Operations
Confluence , (opens new window)
Confluence
, (opens new window)
Teams , (opens new window)
Teams
, (opens new window)
open menu
open menu
Customise sidebar
Customise sidebar
Resize side navigation panel
Spaces
Spaces
/
Jiminny (New)
Jiminny (New)
Platform Team
Platform Team
Add people
Add people
Board actions
Board actions
Share
Automation
Give feedback
Give feedback
Enter full screen
Enter full screen
Summary
Summary
Timeline
Timeline
Backlog
Backlog
Active sprints
Active sprints
Calendar
Calendar
Reports
Reports
Testing Board
Testing Board
List
List
Forms
Forms
Components
Components
Development
Development
Code
Code
8 more tabs
More
8
Add to navigation
As you type to search or apply filters, the board updates with work items to match.
Search on current page
Filter by assignee
Filter assignees by Lukas Kovalik
Filter assignees by Aneliya Angelova
Filter assignees by Nikolay Ivanov...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"SevenShores\\Hubspot\\Exceptions\\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your secondly limit.\",\"errorType\":\"RATE_LIMIT","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SevenShores\\Hubspot\\Exceptions\\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your secondly limit.\",\"errorType\":\"RATE_LIMIT","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Service-Desk - Queues - Platform team - Service space - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Service-Desk - Queues - Platform team - Service space - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Illuminate\\Queue\\MaxAttemptsExceededException: Jiminny\\Jobs\\Activity\\DeleteTeamChurnData has been attempted too many times. — jiminny — app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Illuminate\\Queue\\MaxAttemptsExceededException: Jiminny\\Jobs\\Activity\\DeleteTeamChurnData has been attempted too many times. — jiminny — app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Pull requests · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Userpilot | Ask Jiminny Report Generated","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Userpilot | Ask Jiminny Report Generated","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Problem loading page","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Problem loading page","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Search the CRM - HubSpot docs","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Search the CRM - HubSpot docs","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.16770834,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"bounds":{"left":0.190625,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"bounds":{"left":0.21388888,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.23715279,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.26041666,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip to:","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Top Bar","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Top Bar","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Sidebar","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sidebar","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Main Content","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Main Content","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Space navigation","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Space navigation","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Collapse sidebar [","depth":9,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Collapse sidebar [","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Switch sites or apps","depth":10,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Switch sites or apps","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Go to your Jira homepage","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXComboBox","text":"Search, press enter to navigate to advanced search with your text query","depth":11,"on_screen":true,"help_text":"","placeholder":"Search","role_description":"combo box","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Create","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Create","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Rovo Ask Rovo","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Ask Rovo","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Notifications","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Notifications","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Help","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Help","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Settings","depth":12,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Settings","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"lukas.kovalik@jiminny.com","depth":12,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"lukas.kovalik@jiminny.com","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"For you","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"For you","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Recent","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Recent","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Starred","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Starred","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Apps","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Apps","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Apps","depth":13,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More actions for Apps","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Spaces","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXStaticText","text":"Spaces","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Create space","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Create space","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for spaces","depth":13,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More actions for spaces","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Recent","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Jiminny (New)","depth":17,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny (New)","depth":20,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Jiminny (New)","depth":18,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXMenuButton","text":"Create board","depth":18,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Create board","depth":20,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Jiminny (New)","depth":18,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More actions for Jiminny (New)","depth":20,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Platform Team","depth":19,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":true,"is_selected":false},{"role":"AXStaticText","text":"Platform Team","depth":22,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":20,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Board actions","depth":22,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Capture Team","depth":19,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Capture Team","depth":22,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":20,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Board actions","depth":22,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Enterprise Stability Issues 🤕","depth":19,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Enterprise Stability Issues 🤕","depth":22,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":20,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Board actions","depth":22,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Processing Team","depth":19,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Processing Team","depth":22,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":20,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Board actions","depth":22,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SE Kanban","depth":19,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SE Kanban","depth":22,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":20,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Board actions","depth":22,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Service-Desk","depth":17,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Service-Desk","depth":20,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Service-Desk","depth":18,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More actions for Service-Desk","depth":20,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"More spaces","depth":17,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More spaces","depth":20,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Filters","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Filters","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Filters","depth":13,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More actions for Filters","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Dashboards","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Dashboards","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Create dashboard","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Create dashboard","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Dashboards","depth":13,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More actions for Dashboards","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Operations","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Operations","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Operations","depth":13,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More actions for Operations","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Confluence , (opens new window)","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Confluence","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", (opens new window)","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Teams , (opens new window)","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Teams","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", (opens new window)","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"open menu","depth":14,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"open menu","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Customise sidebar","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Customise sidebar","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Resize side navigation panel","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Spaces","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Spaces","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Jiminny (New)","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny (New)","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Platform Team","depth":10,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Platform Team","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Add people","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Add people","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":10,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Board actions","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Share","depth":10,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXMenuButton","text":"Automation","depth":10,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Give feedback","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Give feedback","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Enter full screen","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Enter full screen","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Summary","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Summary","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Timeline","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Timeline","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Backlog","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Backlog","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Active sprints","depth":13,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Active sprints","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Calendar","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Calendar","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Reports","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Reports","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Testing Board","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Testing Board","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"List","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"List","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Forms","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Forms","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Components","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Components","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Development","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Development","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Code","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Code","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"8 more tabs","depth":11,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"8","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Add to navigation","depth":11,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"As you type to search or apply filters, the board updates with work items to match.","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXTextField","text":"Search on current page","depth":11,"on_screen":true,"placeholder":"Search board","role_description":"text field","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Filter by assignee","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Filter assignees by Lukas Kovalik","depth":11,"on_screen":true,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Filter assignees by Aneliya Angelova","depth":11,"on_screen":true,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Filter assignees by Nikolay Ivanov","depth":11,"on_screen":true,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false}]...
|
6411573323948450900
|
6220965496142091264
|
visual_change
|
accessibility
|
NULL
|
Platform Sprint 3 Q2 - Platform Team - Scrum Board Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Close tab
SevenShores\Hubspot\Exceptions\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your secondly limit.","errorType":"RATE_LIMIT
SevenShores\Hubspot\Exceptions\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your secondly limit.","errorType":"RATE_LIMIT
Service-Desk - Queues - Platform team - Service space - Jira
Service-Desk - Queues - Platform team - Service space - Jira
Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app
Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app
Illuminate\Queue\MaxAttemptsExceededException: Jiminny\Jobs\Activity\DeleteTeamChurnData has been attempted too many times. — jiminny — app
Illuminate\Queue\MaxAttemptsExceededException: Jiminny\Jobs\Activity\DeleteTeamChurnData has been attempted too many times. — jiminny — app
Pull requests · jiminny/app
Pull requests · jiminny/app
Userpilot | Ask Jiminny Report Generated
Userpilot | Ask Jiminny Report Generated
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
Problem loading page
Problem loading page
Search the CRM - HubSpot docs
Search the CRM - HubSpot docs
Jiminny
Jiminny
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Skip to:
Top Bar
Top Bar
Sidebar
Sidebar
Main Content
Main Content
Space navigation
Space navigation
Collapse sidebar [
Collapse sidebar [
Switch sites or apps
Switch sites or apps
Go to your Jira homepage
Search, press enter to navigate to advanced search with your text query
Create
Create
Rovo Ask Rovo
Ask Rovo
Notifications
Notifications
Help
Help
Settings
Settings
[EMAIL]
[EMAIL]
For you
For you
Recent
Recent
Starred
Starred
Apps
Apps
More actions for Apps
More actions for Apps
Spaces
Spaces
Create space
Create space
More actions for spaces
More actions for spaces
Recent
Jiminny (New)
Jiminny (New)
Jiminny (New)
Create board
Create board
More actions for Jiminny (New)
More actions for Jiminny (New)
Platform Team
Platform Team
Board actions
Board actions
Capture Team
Capture Team
Board actions
Board actions
Enterprise Stability Issues 🤕
Enterprise Stability Issues 🤕
Board actions
Board actions
Processing Team
Processing Team
Board actions
Board actions
SE Kanban
SE Kanban
Board actions
Board actions
Service-Desk
Service-Desk
More actions for Service-Desk
More actions for Service-Desk
More spaces
More spaces
Filters
Filters
More actions for Filters
More actions for Filters
Dashboards
Dashboards
Create dashboard
Create dashboard
More actions for Dashboards
More actions for Dashboards
Operations
Operations
More actions for Operations
More actions for Operations
Confluence , (opens new window)
Confluence
, (opens new window)
Teams , (opens new window)
Teams
, (opens new window)
open menu
open menu
Customise sidebar
Customise sidebar
Resize side navigation panel
Spaces
Spaces
/
Jiminny (New)
Jiminny (New)
Platform Team
Platform Team
Add people
Add people
Board actions
Board actions
Share
Automation
Give feedback
Give feedback
Enter full screen
Enter full screen
Summary
Summary
Timeline
Timeline
Backlog
Backlog
Active sprints
Active sprints
Calendar
Calendar
Reports
Reports
Testing Board
Testing Board
List
List
Forms
Forms
Components
Components
Development
Development
Code
Code
8 more tabs
More
8
Add to navigation
As you type to search or apply filters, the board updates with work items to match.
Search on current page
Filter by assignee
Filter assignees by Lukas Kovalik
Filter assignees by Aneliya Angelova
Filter assignees by Nikolay Ivanov...
|
5303
|
NULL
|
NULL
|
NULL
|
|
7271
|
326
|
43
|
2026-05-08T08:35:55.938623+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778229355938_m2.jpg...
|
Firefox
|
Work — Mozilla Firefox
|
True
|
app.datadoghq.com/dashboard/5id-9sv-qmg/ai-feature app.datadoghq.com/dashboard/5id-9sv-qmg/ai-features?fromUser=false&refresh_mode=paused&tile_focus=5187680469773418&from_ts=1772316000000&to_ts=1777475592447&live=false...
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 3 Q2 - Platform Team - Scrum Board Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
SevenShores\Hubspot\Exceptions\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your secondly limit.","errorType":"RATE_LIMIT
SevenShores\Hubspot\Exceptions\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your secondly limit.","errorType":"RATE_LIMIT
Service-Desk - Queues - Platform team - Service space - Jira
Service-Desk - Queues - Platform team - Service space - Jira
Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app
Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app
Illuminate\Queue\MaxAttemptsExceededException: Jiminny\Jobs\Activity\DeleteTeamChurnData has been attempted too many times. — jiminny — app
Illuminate\Queue\MaxAttemptsExceededException: Jiminny\Jobs\Activity\DeleteTeamChurnData has been attempted too many times. — jiminny — app
Pull requests · jiminny/app
Pull requests · jiminny/app
Userpilot | Ask Jiminny Report Generated
Userpilot | Ask Jiminny Report Generated
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
Problem loading page
Problem loading page
Search the CRM - HubSpot docs
Search the CRM - HubSpot docs
Jiminny
Jiminny
New Tab
New Tab
New Tab
New Tab
Dashboards | Datadog
Dashboards | Datadog
app.datadoghq.com/dashboard/5id-9sv-qmg/ai-features?fromUser=false&refresh_mode=paused&tile_focus=[CREDIT_CARD]&from_ts=1772316000000&to_ts=1777475592447&live=false
app.datadoghq.com/dashboard/5id-9sv-qmg/ai-features?fromUser=false&refresh_mode=paused&tile_focus=[CREDIT_CARD]&from_ts=1772316000000&to_ts=1777475592447&live=false
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Skip to main content
Skip to main content
Home
Hide menu
Minimize menu
Go to…
Go to…
Recent
Bits AI
Bits AI
Dashboards
Dashboards
Monitoring
Monitoring
Incident Response
Incident Response
Automation
Automation
Infrastructure
Infrastructure
Cloud Cost
Cloud Cost
APM
APM
Digital Experience
Digital Experience
Software Delivery
Software Delivery
Security
Security
Data Observability
Data Observability
AI Observability
AI Observability
Errors
Errors
Metrics
Metrics
Logs
Logs
Integrations
Integrations
Profile
[EMAIL]
Jiminny, Inc.
Support
Support
NEW Help
NEW
Help
Copyright Datadog, Inc.
2026
Version:
35.112140861
Master Subscription Agreement
Master Subscription Agreement
Privacy Policy
Privacy Policy
Cookie Policy
Cookie Policy
Datadog Status : All Systems Operational
Datadog Status
:
All Systems Operational...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.24700798,"top":0.0518755,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira","depth":5,"bounds":{"left":0.26030585,"top":0.06304868,"width":0.10106383,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SevenShores\\Hubspot\\Exceptions\\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your secondly limit.\",\"errorType\":\"RATE_LIMIT","depth":4,"bounds":{"left":0.24700798,"top":0.08459697,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SevenShores\\Hubspot\\Exceptions\\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your secondly limit.\",\"errorType\":\"RATE_LIMIT","depth":5,"bounds":{"left":0.26030585,"top":0.09577015,"width":0.4644282,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Service-Desk - Queues - Platform team - Service space - Jira","depth":4,"bounds":{"left":0.24700798,"top":0.11731844,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Service-Desk - Queues - Platform team - Service space - Jira","depth":5,"bounds":{"left":0.26030585,"top":0.12849163,"width":0.10721409,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app","depth":4,"bounds":{"left":0.24700798,"top":0.15003991,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app","depth":5,"bounds":{"left":0.26030585,"top":0.16121309,"width":0.17037898,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Illuminate\\Queue\\MaxAttemptsExceededException: Jiminny\\Jobs\\Activity\\DeleteTeamChurnData has been attempted too many times. — jiminny — app","depth":4,"bounds":{"left":0.24700798,"top":0.18276137,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Illuminate\\Queue\\MaxAttemptsExceededException: Jiminny\\Jobs\\Activity\\DeleteTeamChurnData has been attempted too many times. — jiminny — app","depth":5,"bounds":{"left":0.26030585,"top":0.19393456,"width":0.2606383,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Pull requests · jiminny/app","depth":4,"bounds":{"left":0.24700798,"top":0.21548285,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests · jiminny/app","depth":5,"bounds":{"left":0.26030585,"top":0.22665602,"width":0.04537899,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Userpilot | Ask Jiminny Report Generated","depth":4,"bounds":{"left":0.24700798,"top":0.2482043,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Userpilot | Ask Jiminny Report Generated","depth":5,"bounds":{"left":0.26030585,"top":0.25937748,"width":0.07164229,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app","depth":4,"bounds":{"left":0.24700798,"top":0.28092578,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app","depth":5,"bounds":{"left":0.26030585,"top":0.29209897,"width":0.19331782,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Problem loading page","depth":4,"bounds":{"left":0.24700798,"top":0.31364724,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Problem loading page","depth":5,"bounds":{"left":0.26030585,"top":0.32482043,"width":0.037898935,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Search the CRM - HubSpot docs","depth":4,"bounds":{"left":0.24700798,"top":0.3463687,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Search the CRM - HubSpot docs","depth":5,"bounds":{"left":0.26030585,"top":0.3575419,"width":0.05651596,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"bounds":{"left":0.24700798,"top":0.3790902,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"bounds":{"left":0.26030585,"top":0.39026338,"width":0.013131649,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"New Tab","depth":4,"bounds":{"left":0.24700798,"top":0.41181165,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New Tab","depth":5,"bounds":{"left":0.26030585,"top":0.42298484,"width":0.014960106,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"New Tab","depth":4,"bounds":{"left":0.24700798,"top":0.4445331,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New Tab","depth":5,"bounds":{"left":0.26030585,"top":0.4557063,"width":0.014960106,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Dashboards | Datadog","depth":4,"bounds":{"left":0.24700798,"top":0.4772546,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Dashboards | Datadog","depth":5,"bounds":{"left":0.26030585,"top":0.4884278,"width":0.03856383,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"app.datadoghq.com/dashboard/5id-9sv-qmg/ai-features?fromUser=false&refresh_mode=paused&tile_focus=5187680469773418&from_ts=1772316000000&to_ts=1777475592447&live=false","depth":4,"bounds":{"left":0.24700798,"top":0.509976,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"app.datadoghq.com/dashboard/5id-9sv-qmg/ai-features?fromUser=false&refresh_mode=paused&tile_focus=5187680469773418&from_ts=1772316000000&to_ts=1777475592447&live=false","depth":5,"bounds":{"left":0.26030585,"top":0.5211492,"width":0.33494017,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.31432846,"top":0.5171588,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.24983378,"top":0.5442937,"width":0.07413564,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.24983378,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"bounds":{"left":0.26080453,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"bounds":{"left":0.27194148,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.28307846,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.2942154,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Skip to main content","depth":7,"bounds":{"left":0.32795876,"top":0.055067837,"width":0.0033244682,"height":0.007980846},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip to main content","depth":8,"bounds":{"left":0.32962102,"top":0.05905826,"width":0.048204787,"height":0.016759777},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Home","depth":10,"bounds":{"left":0.32662898,"top":0.0518755,"width":0.05319149,"height":0.10973663},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Hide menu","depth":10,"bounds":{"left":0.32862368,"top":0.056664005,"width":0.0066489363,"height":0.015961692},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Minimize menu","depth":10,"bounds":{"left":0.37117687,"top":0.056664005,"width":0.0066489363,"height":0.015961692},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Go to…","depth":9,"bounds":{"left":0.32662898,"top":0.16679968,"width":0.05319149,"height":0.028731046},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Go to…","depth":13,"bounds":{"left":0.33992687,"top":0.17398244,"width":0.014461436,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Recent","depth":12,"bounds":{"left":0.33992687,"top":0.21548285,"width":0.013796543,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Bits AI","depth":11,"bounds":{"left":0.32662898,"top":0.23703113,"width":0.05319149,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Bits AI","depth":14,"bounds":{"left":0.33992687,"top":0.2442139,"width":0.012965426,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Dashboards","depth":11,"bounds":{"left":0.32662898,"top":0.26576218,"width":0.05319149,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Dashboards","depth":14,"bounds":{"left":0.33992687,"top":0.27294493,"width":0.02443484,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Monitoring","depth":11,"bounds":{"left":0.32662898,"top":0.29449323,"width":0.05319149,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Monitoring","depth":14,"bounds":{"left":0.33992687,"top":0.30167598,"width":0.022772606,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Incident Response","depth":11,"bounds":{"left":0.32662898,"top":0.32322428,"width":0.05319149,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Incident Response","depth":14,"bounds":{"left":0.33992687,"top":0.33040702,"width":0.037400264,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Automation","depth":11,"bounds":{"left":0.32662898,"top":0.3519553,"width":0.05319149,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Automation","depth":14,"bounds":{"left":0.33992687,"top":0.35913807,"width":0.024102394,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Infrastructure","depth":11,"bounds":{"left":0.32662898,"top":0.3934557,"width":0.05319149,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Infrastructure","depth":14,"bounds":{"left":0.33992687,"top":0.40063846,"width":0.02825798,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Cloud Cost","depth":11,"bounds":{"left":0.32662898,"top":0.42218676,"width":0.05319149,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Cloud Cost","depth":14,"bounds":{"left":0.33992687,"top":0.4293695,"width":0.021941489,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"APM","depth":11,"bounds":{"left":0.32662898,"top":0.4509178,"width":0.05319149,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"APM","depth":14,"bounds":{"left":0.33992687,"top":0.45810056,"width":0.00930851,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Digital Experience","depth":11,"bounds":{"left":0.32662898,"top":0.47964883,"width":0.05319149,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Digital Experience","depth":14,"bounds":{"left":0.33992687,"top":0.4868316,"width":0.03656915,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Software Delivery","depth":11,"bounds":{"left":0.32662898,"top":0.5083799,"width":0.05319149,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Software Delivery","depth":14,"bounds":{"left":0.33992687,"top":0.51556265,"width":0.03557181,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Security","depth":11,"bounds":{"left":0.32662898,"top":0.5371109,"width":0.05319149,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Security","depth":14,"bounds":{"left":0.33992687,"top":0.5442937,"width":0.016289894,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Data Observability","depth":11,"bounds":{"left":0.32662898,"top":0.565842,"width":0.05319149,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Data Observability","depth":14,"bounds":{"left":0.33992687,"top":0.57302475,"width":0.037400264,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"AI Observability","depth":11,"bounds":{"left":0.32662898,"top":0.594573,"width":0.05319149,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AI Observability","depth":14,"bounds":{"left":0.33992687,"top":0.6017558,"width":0.032081116,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Errors","depth":11,"bounds":{"left":0.32662898,"top":0.6360734,"width":0.05319149,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Errors","depth":14,"bounds":{"left":0.33992687,"top":0.6432562,"width":0.012300532,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Metrics","depth":11,"bounds":{"left":0.32662898,"top":0.66480446,"width":0.05319149,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Metrics","depth":14,"bounds":{"left":0.33992687,"top":0.67198724,"width":0.014960106,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Logs","depth":11,"bounds":{"left":0.32662898,"top":0.6935355,"width":0.05319149,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Logs","depth":14,"bounds":{"left":0.33992687,"top":0.7007183,"width":0.009640957,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Integrations","depth":11,"bounds":{"left":0.32662898,"top":0.89265764,"width":0.05319149,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Integrations","depth":14,"bounds":{"left":0.33992687,"top":0.89984035,"width":0.024933511,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Profile","depth":11,"bounds":{"left":0.32662898,"top":0.9213887,"width":0.05319149,"height":0.028731046},"on_screen":true,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"lukas.kovalik@jiminny.com","depth":15,"bounds":{"left":0.34059176,"top":0.9365523,"width":0.05435505,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Jiminny, Inc.","depth":16,"bounds":{"left":0.34059176,"top":0.9357542,"width":0.020777926,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Support","depth":8,"bounds":{"left":0.32662898,"top":0.9604948,"width":0.026595745,"height":0.039505184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Support","depth":10,"bounds":{"left":0.33294547,"top":0.9828412,"width":0.013962766,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"NEW Help","depth":8,"bounds":{"left":0.35322472,"top":0.9604948,"width":0.026595745,"height":0.039505184},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"NEW","depth":10,"bounds":{"left":0.36269948,"top":0.952514,"width":0.0076462766,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Help","depth":10,"bounds":{"left":0.36253324,"top":0.9828412,"width":0.007978723,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Copyright Datadog, Inc.","depth":11,"bounds":{"left":0.5555186,"top":0.9724661,"width":0.041722074,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2026","depth":11,"bounds":{"left":0.5972407,"top":0.9724661,"width":0.008477394,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Version:","depth":12,"bounds":{"left":0.6087101,"top":0.971668,"width":0.013962766,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"35.112140861","depth":11,"bounds":{"left":0.6090425,"top":0.9724661,"width":0.024102394,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Master Subscription Agreement","depth":11,"bounds":{"left":0.63663566,"top":0.9724661,"width":0.054521278,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Master Subscription Agreement","depth":12,"bounds":{"left":0.63663566,"top":0.9724661,"width":0.054521278,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Privacy Policy","depth":11,"bounds":{"left":0.6946476,"top":0.9724661,"width":0.023105053,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Privacy Policy","depth":12,"bounds":{"left":0.6946476,"top":0.9724661,"width":0.023105053,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Cookie Policy","depth":11,"bounds":{"left":0.7212433,"top":0.9724661,"width":0.02244016,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Cookie Policy","depth":12,"bounds":{"left":0.7212433,"top":0.9724661,"width":0.02244016,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Datadog Status : All Systems Operational","depth":11,"bounds":{"left":0.7471742,"top":0.9724661,"width":0.031083776,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Datadog Status","depth":12,"bounds":{"left":0.7471742,"top":0.9724661,"width":0.02642952,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":13,"bounds":{"left":0.77792555,"top":0.971668,"width":0.0019946808,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"All Systems Operational","depth":13,"bounds":{"left":0.7799202,"top":0.971668,"width":0.04055851,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
7001679311298377024
|
-1854276710258676600
|
visual_change
|
accessibility
|
NULL
|
Platform Sprint 3 Q2 - Platform Team - Scrum Board Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
SevenShores\Hubspot\Exceptions\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your secondly limit.","errorType":"RATE_LIMIT
SevenShores\Hubspot\Exceptions\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your secondly limit.","errorType":"RATE_LIMIT
Service-Desk - Queues - Platform team - Service space - Jira
Service-Desk - Queues - Platform team - Service space - Jira
Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app
Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app
Illuminate\Queue\MaxAttemptsExceededException: Jiminny\Jobs\Activity\DeleteTeamChurnData has been attempted too many times. — jiminny — app
Illuminate\Queue\MaxAttemptsExceededException: Jiminny\Jobs\Activity\DeleteTeamChurnData has been attempted too many times. — jiminny — app
Pull requests · jiminny/app
Pull requests · jiminny/app
Userpilot | Ask Jiminny Report Generated
Userpilot | Ask Jiminny Report Generated
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
Problem loading page
Problem loading page
Search the CRM - HubSpot docs
Search the CRM - HubSpot docs
Jiminny
Jiminny
New Tab
New Tab
New Tab
New Tab
Dashboards | Datadog
Dashboards | Datadog
app.datadoghq.com/dashboard/5id-9sv-qmg/ai-features?fromUser=false&refresh_mode=paused&tile_focus=[CREDIT_CARD]&from_ts=1772316000000&to_ts=1777475592447&live=false
app.datadoghq.com/dashboard/5id-9sv-qmg/ai-features?fromUser=false&refresh_mode=paused&tile_focus=[CREDIT_CARD]&from_ts=1772316000000&to_ts=1777475592447&live=false
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Skip to main content
Skip to main content
Home
Hide menu
Minimize menu
Go to…
Go to…
Recent
Bits AI
Bits AI
Dashboards
Dashboards
Monitoring
Monitoring
Incident Response
Incident Response
Automation
Automation
Infrastructure
Infrastructure
Cloud Cost
Cloud Cost
APM
APM
Digital Experience
Digital Experience
Software Delivery
Software Delivery
Security
Security
Data Observability
Data Observability
AI Observability
AI Observability
Errors
Errors
Metrics
Metrics
Logs
Logs
Integrations
Integrations
Profile
[EMAIL]
Jiminny, Inc.
Support
Support
NEW Help
NEW
Help
Copyright Datadog, Inc.
2026
Version:
35.112140861
Master Subscription Agreement
Master Subscription Agreement
Privacy Policy
Privacy Policy
Cookie Policy
Cookie Policy
Datadog Status : All Systems Operational
Datadog Status
:
All Systems Operational...
|
7270
|
NULL
|
NULL
|
NULL
|
|
7900
|
350
|
43
|
2026-05-08T09:38:29.573854+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778233109573_m2.jpg...
|
Firefox
|
JY-20818 move ask jiminny reports to its own datad JY-20818 move ask jiminny reports to its own datadog metric by LakyLak · Pull Request #12056 · jiminny/app — Work...
|
True
|
github.com/jiminny/app/pull/12056
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 3 Q2 - Platform Team - Scrum Board Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
SevenShores\Hubspot\Exceptions\BadRequest: Client error: `POST [URL_WITH_CREDENTIALS] -4,16 +4,17 @@445namespace Jiminny\Component\Nudge\Job;5namespace Jiminny\Component\Nudge\Job;667+use Carbon\Carbon;7use Illuminate\Bus\Queueable;8use Illuminate\Bus\Queueable;8use Illuminate\Contracts\Queue\ShouldQueue;9use Illuminate\Contracts\Queue\ShouldQueue;9-use Illuminate\Database\Eloquent\Builder;10use Illuminate\Foundation\Bus\Dispatchable;10use Illuminate\Foundation\Bus\Dispatchable;11use Illuminate\Queue\InteractsWithQueue;11use Illuminate\Queue\InteractsWithQueue;12use Illuminate\Queue\SerializesModels;12use Illuminate\Queue\SerializesModels;13use Illuminate\Support\Facades\Log;13use Illuminate\Support\Facades\Log;14use Jiminny\Component\Queue\Constants;14use Jiminny\Component\Queue\Constants;15use Jiminny\Models\Activity;15use Jiminny\Models\Activity;16use Jiminny\Models\Activity\Search;16use Jiminny\Models\Activity\Search;17+use Jiminny\Models\Activity\SearchFilter;17use Jiminny\Models\Nudge;18use Jiminny\Models\Nudge;18use Jiminny\Models\Team;19use Jiminny\Models\Team;1920@@ -34,37 +35,201 @@343535public function handle(): void36public function handle(): void36 {37 {37-/** @var Activity $activity */38+$activity = Activity::with(['user.group'])->uuid($this->activityUuid, false)->firstOrFail();38-$activity = Activity::with(['user'])->uuid($this->activityUuid, false)->firstOrFail();39-40-/** @var Team $team */41$team = Team::with(['users'])->findOrFail($activity->user->team_id);39$team = Team::with(['users'])->findOrFail($activity->user->team_id);424043- Log::info(__METHOD__ . " Running for team $team->id.", [44-'activity_id' => $activity->id,45-'activity_uuid' => $this->activityUuid,46-'team_id' => $team->id,47- ]);48-49$usersIds = $team->users->pluck('id')->toArray();41$usersIds = $team->users->pluck('id')->toArray();504251-$searchesWithImmediateNudges = Activity\Search::with(['nudges'])43+$searchesWithImmediateNudges = Activity\Search::with([44+'nudges' => fn ($q) => $q->where('frequency', Nudge::FREQ_INSTANTLY),45+'filters',46+ ])52 ->whereIn('user_id', $usersIds)47 ->whereIn('user_id', $usersIds)53- ->whereHas('nudges', function (Builder $query) {48+ ->whereHas('nudges', fn ($q) => $q->where('frequency', Nudge::FREQ_INSTANTLY))54-$query->where('frequency', Nudge::FREQ_INSTANTLY);49+ ->get();55- })->get();50+51+$totalSearches = $searchesWithImmediateNudges->count();52+$skippedCount = 0;53+54+$searchesWithImmediateNudges->each(function (Search $search) use ($activity, &$skippedCount): void {55+$matchResult = $this->activityMightMatchSearch($activity, $search);565657-$searchesWithImmediateNudges->each(function (Search $search): void {57+if (! $matchResult['matches']) {58-$search->nudges->each(function (Nudge $nudge): void {58+$skippedCount++;59-// Filter only nudges that are set to be sent instantly59+ Log::info('Pre-filter skipped nudge dispatch', [60-if ($nudge->frequency === Nudge::FREQ_INSTANTLY) {60+'activity_uuid' => $activity->getUuid(),61- Log::info("Dispatching ProcessNudgeSearchJob for nudge $nudge->id.");61+'search_id' => $search->getId(),62+'mismatched_filter' => $matchResult['mismatch_reason'],63+'filter_value' => $matchResult['filter_value'],64+ ]);626563- ProcessNudgeSearchJob::dispatch($nudge);66+return;67+ }646865- Log::info("ProcessNudgeSearchJob dispatched for nudge $nudge->id.");69+$search->nudges->each(fn ($nudge) => ProcessNudgeSearchJob::dispatch($nudge));66- }67- });68 });70 });71+72+if ($totalSearches > 0) {73+ Log::info('Nudge pre-filter results', [74+'activity_uuid' => $activity->getUuid(),75+'total_searches' => $totalSearches,76+'skipped' => $skippedCount,77+'dispatched' => $totalSearches - $skippedCount,78+'skip_rate' => round(($skippedCount / $totalSearches) * 100, 2) . '%',79+ ]);80+ }81+ }82+83+private function activityMightMatchSearch(Activity $activity, Search $search): array84+ {85+foreach ($search->filters as $filter) {86+$filterName = $filter->getFilterProperty();87+88+$result = match ($filterName) {89+'group_id' => $this->checkGroupId($activity, $filter),90+'user_id' => $this->checkUserId($activity, $filter),91+'channel_id' => $this->checkChannelId($activity, $filter),92+'provider_id' => $this->checkProviderId($activity, $filter),93+'category_id' => $this->checkCategoryId($activity, $filter),94+'min_duration' => $this->checkMinDuration($activity, $filter),95+'max_duration' => $this->checkMaxDuration($activity, $filter),96+'not_logged' => $this->checkNotLogged($activity, $filter),97+'only_recorded' => $this->checkOnlyRecorded($activity, $filter),98+'languages' => $this->checkLanguages($activity, $filter),99+'stage_id' => $this->checkStageId($activity, $filter),100+'start_date' => $this->checkStartDate($activity, $filter),101+'end_date' => $this->checkEndDate($activity, $filter),102+default => null, // Unknown filter - can't pre-check, assume might match103+ };104+105+if ($result === false) {106+return [107+'matches' => false,108+'mismatch_reason' => $filterName,109+'filter_value' => $filter->getFilterValue(),110+ ];111+ }112+ }113+114+return ['matches' => true];115+ }116+117+private function checkGroupId(Activity $activity, SearchFilter $filter): ?bool118+ {119+$groupUuid = $activity->user->getGroup()?->getUuid();120+if ($groupUuid === null) {121+return null;122+ }123+124+return $filter->getFilterValue() === $groupUuid ? null : false;125+ }126+127+private function checkUserId(Activity $activity, SearchFilter $filter): ?bool128+ {129+return $filter->getFilterValue() === $activity->user->getUuid() ? null : false;130+ }131+132+private function checkChannelId(Activity $activity, SearchFilter $filter): ?bool133+ {134+return $filter->getFilterValue() === $activity->getType() ? null : false;135+ }136+137+private function checkProviderId(Activity $activity, SearchFilter $filter): ?bool138+ {139+return $filter->getFilterValue() === $activity->getProvider() ? null : false;140+ }141+142+private function checkCategoryId(Activity $activity, SearchFilter $filter): ?bool143+ {144+$categoryId = $activity->getCategory()?->getUuid();145+if ($categoryId === null) {146+return null;147+ }148+149+return $filter->getFilterValue() === $categoryId ? null : false;150+ }151+152+private function checkMinDuration(Activity $activity, SearchFilter $filter): ?bool153+ {154+return $activity->getDuration() >= (float) $filter->getFilterValue() ? null : false;155+ }156+157+private function checkMaxDuration(Activity $activity, SearchFilter $filter): ?bool158+ {159+return $activity->getDuration() <= (float) $filter->getFilterValue() ? null : false;160+ }161+162+private function checkNotLogged(Activity $activity, SearchFilter $filter): ?bool163+ {164+if (! $filter->getFilterValue()) {165+return null;166+ }167+168+$isLogged = $activity->getCrmProviderId() !== null;169+$isInternal = $activity->isInternal();170+171+return (! $isLogged || $isInternal) ? null : false;172+ }173+174+private function checkOnlyRecorded(Activity $activity, SearchFilter $filter): ?bool175+ {176+$filterValue = (int) $filter->getFilterValue();177+$hasRecording = $activity->recording_state !== Activity::RECORDING_OFF;178+179+return match ($filterValue) {180+1 => $hasRecording ? null : false, // Only recorded181+2 => ! $hasRecording ? null : false, // Only non-recorded182+default => null,183+ };184+ }185+186+private function checkStageId(Activity $activity, SearchFilter $filter): ?bool187+ {188+$stageId = $activity->getStage()?->getUuid();189+if ($stageId === null) {190+return null; // No stage, let ES handle191+ }192+193+return $filter->getFilterValue() === $stageId ? null : false;194+ }195+196+private function checkStartDate(Activity $activity, SearchFilter $filter): ?bool197+ {198+$startTime = $activity->getActualStartTime();199+if ($startTime === null) {200+return null;201+ }202+203+$filterDate = Carbon::parse($filter->getFilterValue());204+205+return $startTime->gte($filterDate) ? null : false;206+ }207+208+private function checkEndDate(Activity $activity, SearchFilter $filter): ?bool209+ {210+$endTime = $activity->getActualEndTime();211+if ($endTime === null) {212+return null;213+ }214+215+$filterDate = Carbon::parse($filter->getFilterValue())->endOfDay();216+217+return $endTime->lte($filterDate) ? null : false;218+ }219+220+private function checkLanguages(Activity $activity, SearchFilter $filter): ?bool221+ {222+$activityLanguage = $activity->getLanguageCode();223+if ($activityLanguage === null) {224+return null;225+ }226+227+// Filter values are always base language codes (e.g., 'en', 'fr').228+// Extract base code from activity locale (e.g., en_GB -> en) to match ES query behavior.229+// See LanguageFilterDefinition::getQueries() which uses regex: $language . '_[a-z]{2}'230+$activityLangCode = explode('_', $activityLanguage)[0];231+$filterLanguage = $filter->getFilterValue();232+233+return $activityLangCode === $filterLanguage ? null : false;69 }234 }70}235}</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>Jy 20493 smart instant nudge pre filtering by niko</tabTitle>” with “<selection>@@ -4,16 +4,17 @@445namespace Jiminny\Component\Nudge\Job;5namespace Jiminny\Component\Nudge\Job;667+use Carbon\Carbon;7use Illuminate\Bus\Queueable;8use Illuminate\Bus\Queueable;8use Illuminate\Contracts\Queue\ShouldQueue;9use Illuminate\Contracts\Queue\ShouldQueue;9-use Illuminate\Database\Eloquent\Builder;10use Illuminate\Foundation\Bus\Dispatchable;10use Illuminate\Foundation\Bus\Dispatchable;11use Illuminate\Queue\InteractsWithQueue;11use Illuminate\Queue\InteractsWithQueue;12use Illuminate\Queue\SerializesModels;12use Illuminate\Queue\SerializesModels;13use Illuminate\Support\Facades\Log;13use Illuminate\Support\Facades\Log;14use Jiminny\Component\Queue\Constants;14use Jiminny\Component\Queue\Constants;15use Jiminny\Models\Activity;15use Jiminny\Models\Activity;16use Jiminny\Models\Activity\Search;16use Jiminny\Models\Activity\Search;17+use Jiminny\Models\Activity\SearchFilter;17use Jiminny\Models\Nudge;18use Jiminny\Models\Nudge;18use Jiminny\Models\Team;19use Jiminny\Models\Team;1920@@ -34,37 +35,201 @@343535public function handle(): void36public function handle(): void36 {37 {37-/** @var Activity $activity */38+$activity = Activity::with(['user.group'])->uuid($this->activityUuid, false)->firstOrFail();38-$activity = Activity::with(['user'])->uuid($this->activityUuid, false)->firstOrFail();39-40-/** @var Team $team */41$team = Team::with(['users'])->findOrFail($activity->user->team_id);39$team = Team::with(['users'])->findOrFail($activity->user->team_id);424043- Log::info(__METHOD__ . " Running for team $team->id.", [44-'activity_id' => $activity->id,45-'activity_uuid' => $this->activityUuid,46-'team_id' => $team->id,47- ]);48-49$usersIds = $team->users->pluck('id')->toArray();41$usersIds = $team->users->pluck('id')->toArray();504251-$searchesWithImmediateNudges = Activity\Search::with(['nudges'])43+$searchesWithImmediateNudges = Activity\Search::with([44+'nudges' => fn ($q) => $q->where('frequency', Nudge::FREQ_INSTANTLY),45+'filters',46+ ])52 ->whereIn('user_id', $usersIds)47 ->whereIn('user_id', $usersIds)53- ->whereHas('nudges', function (Builder $query) {48+ ->whereHas('nudges', fn ($q) => $q->where('frequency', Nudge::FREQ_INSTANTLY))54-$query->where('frequency', Nudge::FREQ_INSTANTLY);49+ ->get();55- })->get();50+51+$totalSearches = $searchesWithImmediateNudges->count();52+$skippedCount = 0;53+54+$searchesWithImmediateNudges->each(function (Search $search) use ($activity, &$skippedCount): void {55+$matchResult = $this->activityMightMatchSearch($activity, $search);565657-$searchesWithImmediateNudges->each(function (Search $search): void {57+if (! $matchResult['matches']) {58-$search->nudges->each(function (Nudge $nudge): void {58+$skippedCount++;59-// Filter only nudges that are set to be sent instantly59+ Log::info('Pre-filter skipped nudge dispatch', [60-if ($nudge->frequency === Nudge::FREQ_INSTANTLY) {60+'activity_uuid' => $activity->getUuid(),61- Log::info("Dispatching ProcessNudgeSearchJob for nudge $nudge->id.");61+'search_id' => $search->getId(),62+'mismatched_filter' => $matchResult['mismatch_reason'],63+'filter_value' => $matchResult['filter_value'],64+ ]);626563- ProcessNudgeSearchJob::dispatch($nudge);66+return;67+ }646865- Log::info("ProcessNudgeSearchJob dispatched for nudge $nudge->id.");69+$search->nudges->each(fn ($nudge) => ProcessNudgeSearchJob::dispatch($nudge));66- }67- });68 });70 });71+72+if ($totalSearches > 0) {73+ Log::info('Nudge pre-filter results', [74+'activity_uuid' => $activity->getUuid(),75+'total_searches' => $totalSearches,76+'skipped' => $skippedCount,77+'dispatched' => $totalSearches - $skippedCount,78+'skip_rate' => round(($skippedCount / $totalSearches) * 100, 2) . '%',79+ ]);80+ }81+ }82+83+private function activityMightMatchSearch(Activity $activity, Search $search): array84+ {85+foreach ($search->filters as $filter) {86+$filterName = $filter->getFilterProperty();87+88+$result = match ($filterName) {89+'group_id' => $this->checkGroupId($activity, $filter),90+'user_id' => $this->checkUserId($activity, $filter),91+'channel_id' => $this->checkChannelId($activity, $filter),92+'provider_id' => $this->checkProviderId($activity, $filter),93+'category_id' => $this->checkCategoryId($activity, $filter),94+'min_duration' => $this->checkMinDuration($activity, $filter),95+'max_duration' => $this->checkMaxDuration($activity, $filter),96+'not_logged' => $this->checkNotLogged($activity, $filter),97+'only_recorded' => $this->checkOnlyRecorded($activity, $filter),98+'languages' => $this->checkLanguages($activity, $filter),99+'stage_id' => $this->checkStageId($activity, $filter),100+'start_date' => $this->checkStartDate($activity, $filter),101+'end_date' => $this->checkEndDate($activity, $filter),102+default => null, // Unknown filter - can't pre-check, assume might match103+ };104+105+if ($result === false) {106+return [107+'matches' => false,108+'mismatch_reason' => $filterName,109+'filter_value' => $filter->getFilterValue(),110+ ];111+ }112+ }113+114+return ['matches' => true];115+ }116+117+private function checkGroupId(Activity $activity, SearchFilter $filter): ?bool118+ {119+$groupUuid = $activity->user->getGroup()?->getUuid();120+if ($groupUuid === null) {121+return null;122+ }123+124+return $filter->getFilterValue() === $groupUuid ? null : false;125+ }126+127+private function checkUserId(Activity $activity, SearchFilter $filter): ?bool128+ {129+return $filter->getFilterValue() === $activity->user->getUuid() ? null : false;130+ }131+132+private function checkChannelId(Activity $activity, SearchFilter $filter): ?bool133+ {134+return $filter->getFilterValue() === $activity->getType() ? null : false;135+ }136+137+private function checkProviderId(Activity $activity, SearchFilter $filter): ?bool138+ {139+return $filter->getFilterValue() === $activity->getProvider() ? null : false;140+ }141+142+private function checkCategoryId(Activity $activity, SearchFilter $filter): ?bool143+ {144+$categoryId = $activity->getCategory()?->getUuid();145+if ($categoryId === null) {146+return null;147+ }148+149+return $filter->getFilterValue() === $categoryId ? null : false;150+ }151+152+private function checkMinDuration(Activity $activity, SearchFilter $filter): ?bool153+ {154+return $activity->getDuration() >= (float) $filter->getFilterValue() ? null : false;155+ }156+157+private function checkMaxDuration(Activity $activity, SearchFilter $filter): ?bool158+ {159+return $activity->getDuration() <= (float) $filter->getFilterValue() ? null : false;160+ }161+162+private function checkNotLogged(Activity $activity, SearchFilter $filter): ?bool163+ {164+if (! $filter->getFilterValue()) {165+return null;166+ }167+168+$isLogged = $activity->getCrmProviderId() !== null;169+$isInternal = $activity->isInternal();170+171+return (! $isLogged || $isInternal) ? null : false;172+ }173+174+private function checkOnlyRecorded(Activity $activity, SearchFilter $filter): ?bool175+ {176+$filterValue = (int) $filter->getFilterValue();177+$hasRecording = $activity->recording_state !== Activity::RECORDING_OFF;178+179+return match ($filterValue) {180+1 => $hasRecording ? null : false, // Only recorded181+2 => ! $hasRecording ? null : false, // Only non-recorded182+default => null,183+ };184+ }185+186+private function checkStageId(Activity $activity, SearchFilter $filter): ?bool187+ {188+$stageId = $activity->getStage()?->getUuid();189+if ($stageId === null) {190+return null; // No stage, let ES handle191+ }192+193+return $filter->getFilterValue() === $stageId ? null : false;194+ }195+196+private function checkStartDate(Activity $activity, SearchFilter $filter): ?bool197+ {198+$startTime = $activity->getActualStartTime();199+if ($startTime === null) {200+return null;201+ }202+203+$filterDate = Carbon::parse($filter->getFilterValue());204+205+return $startTime->gte($filterDate) ? null : false;206+ }207+208+private function checkEndDate(Activity $activity, SearchFilter $filter): ?bool209+ {210+$endTime = $activity->getActualEndTime();211+if ($endTime === null) {212+return null;213+ }214+215+$filterDate = Carbon::parse($filter->getFilterValue())->endOfDay();216+217+return $endTime->lte($filterDate) ? null : false;218+ }219+220+private function checkLanguages(Activity $activity, SearchFilter $filter): ?bool221+ {222+$activityLanguage = $activity->getLanguageCode();223+if ($activityLanguage === null) {224+return null;225+ }226+227+// Filter values are always base language codes (e.g., 'en', 'fr').228+// Extract base code from activity locale (e.g., en_GB -> en) to match ES query behavior.229+// See LanguageFilterDefinition::getQueries() which uses regex: $language . '_[a-z]{2}'230+$activityLangCode = explode('_', $activityLanguage)[0];231+$filterLanguage = $filter->getFilterValue();232+233+return $activityLangCode === $filterLanguage ? null : false;69 }234 }70}235}</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Expand
Listen
Gemini said
Gemini said
This code selection introduces a
pre-filtering mechanism
to the
Jiminny\Component\Nudge\Job
namespace. The primary goal is to optimize performance by validating an activity against search criteria in-memory before dispatching costly background jobs.
Core Functionality Changes
Core Functionality Changes
Selective Loading:
The
handle()
method now eager-loads
user.group
for activities and specifically filters for
FREQ_INSTANTLY
nudges and their associated search filters.
Pre-Dispatch Validation:
Instead of dispatching jobs for every instant nudge, the system now calls
activityMightMatchSearch()
.
Short-Circuiting:
If an activity fails a pre-filter check (e.g., mismatched user ID or duration), the job dispatch is skipped, and the event is logged with the specific mismatch reason.
Performance Metrics:
Adds summary logging at the end of the process to track:
Total searches processed.
Number of skipped dispatches.
The "Skip Rate" percentage.
Implemented Filter Checks
Implemented Filter Checks
The logic includes a
match
expression to validate various activity attributes against
SearchFilter
values:
Identity & Metadata:
Matches for
group_id
,
user_id
,
channel_id
, and
provider_id
.
Temporal & Duration:
* Validates
min_duration
and
max_duration
.
Checks
start_date
and
end_date
using Carbon parsing.
Activity State:
*
Logging:
Determines if an activity is logged to a CRM or is internal via
checkNotLogged
.
Recording:
Uses
checkOnlyRecorded
to filter based on whether a recording exists.
Categorization:
Checks for
category_id
,
stage_id
, and
languages
.
Note:
The language check specifically extracts base codes (e.g.,
en
from
en_GB
) to align with Elasticsearch behavior.
Logic Design
Logic Design
Nullable Returns:
Filter methods return
null
if a match is possible (or cannot be determined), and
false
only when a definitive mismatch is found.
Safe Fallback:
If a filter type is unknown (
default
), the system assumes a match and proceeds to dispatch, ensuring no false negatives.
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
You said what is the logic behind diff. Act as code reviewer. First review the changes then explain it and then evaluate. Try to find potential issues and bottlenecks
You said
what is the logic behind diff. Act as code reviewer. First review the changes then explain it and then evaluate. Try to find potential issues and bottlenecks
Expand
Listen
Show more options
Show thinking
Gemini said
Gemini said
Here is a review of the changes provided in the diff, broken down by your requested structure.
1. Review of Changes
1. Review of Changes
This PR refactors the
ProcessNudgeSearchJob
dispatching mechanism within the
handle()
method.
Query Optimization:
Eager loads necessary relationships (
user.group
,
filters
) and scopes the
nudges
relationship at the database level to only fetch
FREQ_INSTANTLY
records.
In-Memory Filtering:
Introduces a pre-filtering mechanism (
activityMightMatchSearch
) that checks the
Activity
against
SearchFilter
criteria before deciding to dispatch a job.
Helper Methods:
Adds 13 private
check*
methods to handle the specific comparison logic for different filter types (e.g., duration, dates, categories, stages).
Observability:
Adds structured logging to record exactly why a nudge was skipped and outputs a summary report (total, skipped, dispatched, skip rate) at the end of the execution.
2. Explanation of Logic
2. Explanation of Logic
The core philosophy of this change is
"veto-based short-circuiting"
.
Previously, the job fetched all searches with instant nudges for a team's users and blindly dispatched a queue job for every single one. The heavy lifting of deciding if the activity actually matched the search was likely deferred to the queue worker and Elasticsearch.
Now, the code evaluates the filters in the current process:
It iterates through each
Search
and its associated
SearchFilter
s.
It routes the filter to a specific
check*
method using a
match
expression based on the filter's property name.
The Veto:
The
check*
methods are designed to return
false
only if there is an absolute mismatch
(e.g., the filter requires a minimum duration of 10, but the activity is 5).
The Pass:
If the filter matches, or if the activity lacks the data needed to make a firm decision (e.g., no stage is assigned, or the filter type is unrecognized), the method returns
null
. This acts as a pass, delegating the final strict evaluation to Elasticsearch later in the pipeline.
If any filter returns
false
, the search is skipped, saving a queue dispatch.
3. Evaluation
3. Evaluation
Overall, this is a
highly effective performance optimization
.
Pros:
It significantly reduces queue bloat. By filtering out obvious mismatches in-memory, you save the overhead of serializing, dispatching, picking up, and processing jobs that are destined to fail or do nothing. The use of
match
makes the routing exceptionally clean, and the nullable return design is a smart way to avoid false negatives.
Cons/Trade-offs:
You are trading background queue worker time for a slight increase in synchronous memory and CPU usage on the current job. However, queue I/O is almost always more expensive than simple in-memory comparisons, making this a worthwhile trade.
4. Potential Issues & Bottlenecks
4. Potential Issues & Bottlenecks
While the logic is sound, there are a few architectural bottlenecks and risks introduced or maintained in this diff:
Potential N+1 Query / Lazy Loading Issues:
In the
handle
method, the activity is loaded with
Activity::with(['user.group'])
. However, inside your new
check*
methods, you are calling:
$activity->getCategory()?->getUuid()
$activity->getStage()?->getUuid()
If
category
and
stage
are Eloquent relationships and are not eager-loaded on the original
$activity
model, calling these methods inside a loop of
$totalSearches
will trigger lazy-loaded database queries.
Fix:
Update line 38 to:
$activity = Activity::with(['user.group', 'category', 'stage'])->...
Massive Memory Consumption (Pre-existing but critical):
Lines 39-41:
PHP
Download code
Copy code
$team
= Team::with([
'users'
])->findOrFail(
$activity
->user->team_id);
$usersIds
=
$team
->users->pluck(
'id'
)->toArray();
If a team has thousands of users,
Team::with(['users'])
hydrates thousands of full Eloquent User models into memory just to extract their IDs.
Fix:
Bypass hydrating the models entirely by querying the relationship directly:
$usersIds = $team->users()->pluck('id')->toArray();
Repeated Carbon Parsing in Loops:
In
checkStartDate
and
checkEndDate
, you parse the filter date:
Carbon::parse($filter->getFilterValue())
. If the same date filter applies to multiple searches, Carbon is being instantiated repeatedly in the loop. While Carbon is relatively fast, doing this hundreds of times adds unnecessary CPU cycles.
Fix:
This is a minor nitpick, but if performance is the absolute goal, you could memoize/cache the parsed filter values within the job.
Loose Type Comparisons:
In methods like
checkChannelId
or
checkLanguages
, you are using strict equality (
===
). Ensure that
$filter->getFilterValue()
(which is typically returned as a string from a database payload) matches the exact type returned by
$activity->getType()
or
$activityLangCode
. If one is an integer
1
and the other is a string
"1"
, the strict check will return
false
, incorrectly preventing the nudge from sending.
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said what would be your suggestion?
You said
what would be your suggestion?
Listen
Show more options
Show thinking
Gemini said
Gemini said
Here are actionable suggestions to address the potential issues and bottlenecks identified in the review. These optimizations focus on reducing memory footprint, preventing lazy-loading, and ensuring data type resilience.
1. Fix the N+1 Query Risk (Eager Loading)
1. Fix the N+1 Query Risk (Eager Loading)
Your
checkCategoryId
and
checkStageId
methods call
$activity->getCategory()
and
$activity->getStage()
. If these relationships aren't eager-loaded, Laravel will execute a new database query for every check inside the loop.
Suggestion:
Add
category
and
stage
to the initial eager-load array.
PHP
Download code
Copy code
// Before (Line 38)
$activity
= Activity::with([
'user.group'
])->uuid(
$this
->activityUuid,
false
)->firstOrFail();
// After
$activity
= Activity::with([
'user.group'
,
'category'
,
'stage'
])->uuid(
$this
->activityUuid,
false
)->firstOrFail();
2. Drastically Reduce Memory Usage
2. Drastically Reduce Memory Usage
Currently, you are hydrating full Eloquent
User
models into memory just to extract their IDs. If a team has hundreds or thousands of users, this will spike memory usage and potentially crash the worker.
Suggestion:
Use the relationship query builder to perform the
pluck
directly at the database level, bypassing Eloquent model hydration entirely.
PHP
Download code
Copy code
// Before (Lines 39-41)
$team
= Team::with([
'users'
])->findOrFail(
$activity
->user->team_id);
$usersIds
=
$team
->users->pluck(
'id'
)->toArray();
// After (No need to eager load 'users' on the Team model anymore)
$team
= Team::findOrFail(
$activity
->user->team_id);
$usersIds
=
$team
->users()->pluck(
'users.id'
)->toArray();
// Note the `()` after users
3. Harden Type Comparisons
3. Harden Type Comparisons
Since Elasticsearch and databases often return IDs or filter values as strings, strict comparison (
===
) against an Eloquent model's attribute (which might be cast to an integer) can cause false negatives.
Suggestion:
Cast your values before comparison, or use loose equality (
==
) if you are absolutely certain of the payload structure.
PHP
Download code
Copy code
// Example for checkChannelId (Lines 132-135)
private
function...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.24700798,"top":0.0518755,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira","depth":5,"bounds":{"left":0.26030585,"top":0.06304868,"width":0.10106383,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SevenShores\\Hubspot\\Exceptions\\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your secondly limit.\",\"errorType\":\"RATE_LIMIT","depth":4,"bounds":{"left":0.24700798,"top":0.08459697,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SevenShores\\Hubspot\\Exceptions\\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your secondly limit.\",\"errorType\":\"RATE_LIMIT","depth":5,"bounds":{"left":0.26030585,"top":0.09577015,"width":0.4644282,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Service-Desk - Queues - Platform team - Service space - Jira","depth":4,"bounds":{"left":0.24700798,"top":0.11731844,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Service-Desk - Queues - Platform team - Service space - Jira","depth":5,"bounds":{"left":0.26030585,"top":0.12849163,"width":0.10721409,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app","depth":4,"bounds":{"left":0.24700798,"top":0.15003991,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app","depth":5,"bounds":{"left":0.26030585,"top":0.16121309,"width":0.17037898,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Illuminate\\Queue\\MaxAttemptsExceededException: Jiminny\\Jobs\\Activity\\DeleteTeamChurnData has been attempted too many times. — jiminny — app","depth":4,"bounds":{"left":0.24700798,"top":0.18276137,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Illuminate\\Queue\\MaxAttemptsExceededException: Jiminny\\Jobs\\Activity\\DeleteTeamChurnData has been attempted too many times. — jiminny — app","depth":5,"bounds":{"left":0.26030585,"top":0.19393456,"width":0.2606383,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20818 move ask jiminny reports to its own datadog metric by LakyLak · Pull Request #12056 · jiminny/app","depth":4,"bounds":{"left":0.24700798,"top":0.21548285,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"JY-20818 move ask jiminny reports to its own datadog metric by LakyLak · Pull Request #12056 · jiminny/app","depth":5,"bounds":{"left":0.26030585,"top":0.22665602,"width":0.18899602,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.31432846,"top":0.22266561,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Userpilot | Ask Jiminny Report Generated","depth":4,"bounds":{"left":0.24700798,"top":0.2482043,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Userpilot | Ask Jiminny Report Generated","depth":5,"bounds":{"left":0.26030585,"top":0.25937748,"width":0.07164229,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app","depth":4,"bounds":{"left":0.24700798,"top":0.28092578,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app","depth":5,"bounds":{"left":0.26030585,"top":0.29209897,"width":0.19331782,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Problem loading page","depth":4,"bounds":{"left":0.24700798,"top":0.31364724,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Problem loading page","depth":5,"bounds":{"left":0.26030585,"top":0.32482043,"width":0.037898935,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Search the CRM - HubSpot docs","depth":4,"bounds":{"left":0.24700798,"top":0.3463687,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Search the CRM - HubSpot docs","depth":5,"bounds":{"left":0.26030585,"top":0.3575419,"width":0.05651596,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"bounds":{"left":0.24700798,"top":0.3790902,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"bounds":{"left":0.26030585,"top":0.39026338,"width":0.013131649,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"New Tab","depth":4,"bounds":{"left":0.24700798,"top":0.41181165,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New Tab","depth":5,"bounds":{"left":0.26030585,"top":0.42298484,"width":0.014960106,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"New Tab","depth":4,"bounds":{"left":0.24700798,"top":0.4445331,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New Tab","depth":5,"bounds":{"left":0.26030585,"top":0.4557063,"width":0.014960106,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Dashboards | Datadog","depth":4,"bounds":{"left":0.24700798,"top":0.4772546,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Dashboards | Datadog","depth":5,"bounds":{"left":0.26030585,"top":0.4884278,"width":0.03856383,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"AI Features | Datadog","depth":4,"bounds":{"left":0.24700798,"top":0.509976,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AI Features | Datadog","depth":5,"bounds":{"left":0.26030585,"top":0.5211492,"width":0.037400264,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jy 20493 smart instant nudge pre filtering by nikolaybiaivanov · Pull Request #12053 · jiminny/app","depth":4,"bounds":{"left":0.24700798,"top":0.54269755,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jy 20493 smart instant nudge pre filtering by nikolaybiaivanov · Pull Request #12053 · jiminny/app","depth":5,"bounds":{"left":0.26030585,"top":0.55387074,"width":0.17037898,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.24983378,"top":0.57701516,"width":0.07413564,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.24983378,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"bounds":{"left":0.26080453,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"bounds":{"left":0.27194148,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.28307846,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.2942154,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":7,"bounds":{"left":0.43168217,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":7,"bounds":{"left":0.44365028,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"WORK, Google Account: lukas.kovalik@jiminny.com","depth":12,"bounds":{"left":0.4409907,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Main menu","depth":12,"bounds":{"left":0.33061835,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Chat","depth":12,"bounds":{"left":0.41306517,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open menu for conversation actions.","depth":12,"bounds":{"left":0.42636302,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Conversation with Gemini","depth":15,"bounds":{"left":0.32629654,"top":0.14764565,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":16,"bounds":{"left":0.32629654,"top":0.15003991,"width":0.1200133,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy prompt","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said I’m on page “<tabTitle>Jy 20493 smart instant nudge pre filtering by niko</tabTitle>” with “<selection>@@ -4,16 +4,17 @@445namespace Jiminny\\Component\\Nudge\\Job;5namespace Jiminny\\Component\\Nudge\\Job;667+use Carbon\\Carbon;7use Illuminate\\Bus\\Queueable;8use Illuminate\\Bus\\Queueable;8use Illuminate\\Contracts\\Queue\\ShouldQueue;9use Illuminate\\Contracts\\Queue\\ShouldQueue;9-use Illuminate\\Database\\Eloquent\\Builder;10use Illuminate\\Foundation\\Bus\\Dispatchable;10use Illuminate\\Foundation\\Bus\\Dispatchable;11use Illuminate\\Queue\\InteractsWithQueue;11use Illuminate\\Queue\\InteractsWithQueue;12use Illuminate\\Queue\\SerializesModels;12use Illuminate\\Queue\\SerializesModels;13use Illuminate\\Support\\Facades\\Log;13use Illuminate\\Support\\Facades\\Log;14use Jiminny\\Component\\Queue\\Constants;14use Jiminny\\Component\\Queue\\Constants;15use Jiminny\\Models\\Activity;15use Jiminny\\Models\\Activity;16use Jiminny\\Models\\Activity\\Search;16use Jiminny\\Models\\Activity\\Search;17+use Jiminny\\Models\\Activity\\SearchFilter;17use Jiminny\\Models\\Nudge;18use Jiminny\\Models\\Nudge;18use Jiminny\\Models\\Team;19use Jiminny\\Models\\Team;1920@@ -34,37 +35,201 @@343535public function handle(): void36public function handle(): void36 {37 {37-/** @var Activity $activity */38+$activity = Activity::with(['user.group'])->uuid($this->activityUuid, false)->firstOrFail();38-$activity = Activity::with(['user'])->uuid($this->activityUuid, false)->firstOrFail();39-40-/** @var Team $team */41$team = Team::with(['users'])->findOrFail($activity->user->team_id);39$team = Team::with(['users'])->findOrFail($activity->user->team_id);424043- Log::info(__METHOD__ . " Running for team $team->id.", [44-'activity_id' => $activity->id,45-'activity_uuid' => $this->activityUuid,46-'team_id' => $team->id,47- ]);48-49$usersIds = $team->users->pluck('id')->toArray();41$usersIds = $team->users->pluck('id')->toArray();504251-$searchesWithImmediateNudges = Activity\\Search::with(['nudges'])43+$searchesWithImmediateNudges = Activity\\Search::with([44+'nudges' => fn ($q) => $q->where('frequency', Nudge::FREQ_INSTANTLY),45+'filters',46+ ])52 ->whereIn('user_id', $usersIds)47 ->whereIn('user_id', $usersIds)53- ->whereHas('nudges', function (Builder $query) {48+ ->whereHas('nudges', fn ($q) => $q->where('frequency', Nudge::FREQ_INSTANTLY))54-$query->where('frequency', Nudge::FREQ_INSTANTLY);49+ ->get();55- })->get();50+51+$totalSearches = $searchesWithImmediateNudges->count();52+$skippedCount = 0;53+54+$searchesWithImmediateNudges->each(function (Search $search) use ($activity, &$skippedCount): void {55+$matchResult = $this->activityMightMatchSearch($activity, $search);565657-$searchesWithImmediateNudges->each(function (Search $search): void {57+if (! $matchResult['matches']) {58-$search->nudges->each(function (Nudge $nudge): void {58+$skippedCount++;59-// Filter only nudges that are set to be sent instantly59+ Log::info('Pre-filter skipped nudge dispatch', [60-if ($nudge->frequency === Nudge::FREQ_INSTANTLY) {60+'activity_uuid' => $activity->getUuid(),61- Log::info("Dispatching ProcessNudgeSearchJob for nudge $nudge->id.");61+'search_id' => $search->getId(),62+'mismatched_filter' => $matchResult['mismatch_reason'],63+'filter_value' => $matchResult['filter_value'],64+ ]);626563- ProcessNudgeSearchJob::dispatch($nudge);66+return;67+ }646865- Log::info("ProcessNudgeSearchJob dispatched for nudge $nudge->id.");69+$search->nudges->each(fn ($nudge) => ProcessNudgeSearchJob::dispatch($nudge));66- }67- });68 });70 });71+72+if ($totalSearches > 0) {73+ Log::info('Nudge pre-filter results', [74+'activity_uuid' => $activity->getUuid(),75+'total_searches' => $totalSearches,76+'skipped' => $skippedCount,77+'dispatched' => $totalSearches - $skippedCount,78+'skip_rate' => round(($skippedCount / $totalSearches) * 100, 2) . '%',79+ ]);80+ }81+ }82+83+private function activityMightMatchSearch(Activity $activity, Search $search): array84+ {85+foreach ($search->filters as $filter) {86+$filterName = $filter->getFilterProperty();87+88+$result = match ($filterName) {89+'group_id' => $this->checkGroupId($activity, $filter),90+'user_id' => $this->checkUserId($activity, $filter),91+'channel_id' => $this->checkChannelId($activity, $filter),92+'provider_id' => $this->checkProviderId($activity, $filter),93+'category_id' => $this->checkCategoryId($activity, $filter),94+'min_duration' => $this->checkMinDuration($activity, $filter),95+'max_duration' => $this->checkMaxDuration($activity, $filter),96+'not_logged' => $this->checkNotLogged($activity, $filter),97+'only_recorded' => $this->checkOnlyRecorded($activity, $filter),98+'languages' => $this->checkLanguages($activity, $filter),99+'stage_id' => $this->checkStageId($activity, $filter),100+'start_date' => $this->checkStartDate($activity, $filter),101+'end_date' => $this->checkEndDate($activity, $filter),102+default => null, // Unknown filter - can't pre-check, assume might match103+ };104+105+if ($result === false) {106+return [107+'matches' => false,108+'mismatch_reason' => $filterName,109+'filter_value' => $filter->getFilterValue(),110+ ];111+ }112+ }113+114+return ['matches' => true];115+ }116+117+private function checkGroupId(Activity $activity, SearchFilter $filter): ?bool118+ {119+$groupUuid = $activity->user->getGroup()?->getUuid();120+if ($groupUuid === null) {121+return null;122+ }123+124+return $filter->getFilterValue() === $groupUuid ? null : false;125+ }126+127+private function checkUserId(Activity $activity, SearchFilter $filter): ?bool128+ {129+return $filter->getFilterValue() === $activity->user->getUuid() ? null : false;130+ }131+132+private function checkChannelId(Activity $activity, SearchFilter $filter): ?bool133+ {134+return $filter->getFilterValue() === $activity->getType() ? null : false;135+ }136+137+private function checkProviderId(Activity $activity, SearchFilter $filter): ?bool138+ {139+return $filter->getFilterValue() === $activity->getProvider() ? null : false;140+ }141+142+private function checkCategoryId(Activity $activity, SearchFilter $filter): ?bool143+ {144+$categoryId = $activity->getCategory()?->getUuid();145+if ($categoryId === null) {146+return null;147+ }148+149+return $filter->getFilterValue() === $categoryId ? null : false;150+ }151+152+private function checkMinDuration(Activity $activity, SearchFilter $filter): ?bool153+ {154+return $activity->getDuration() >= (float) $filter->getFilterValue() ? null : false;155+ }156+157+private function checkMaxDuration(Activity $activity, SearchFilter $filter): ?bool158+ {159+return $activity->getDuration() <= (float) $filter->getFilterValue() ? null : false;160+ }161+162+private function checkNotLogged(Activity $activity, SearchFilter $filter): ?bool163+ {164+if (! $filter->getFilterValue()) {165+return null;166+ }167+168+$isLogged = $activity->getCrmProviderId() !== null;169+$isInternal = $activity->isInternal();170+171+return (! $isLogged || $isInternal) ? null : false;172+ }173+174+private function checkOnlyRecorded(Activity $activity, SearchFilter $filter): ?bool175+ {176+$filterValue = (int) $filter->getFilterValue();177+$hasRecording = $activity->recording_state !== Activity::RECORDING_OFF;178+179+return match ($filterValue) {180+1 => $hasRecording ? null : false, // Only recorded181+2 => ! $hasRecording ? null : false, // Only non-recorded182+default => null,183+ };184+ }185+186+private function checkStageId(Activity $activity, SearchFilter $filter): ?bool187+ {188+$stageId = $activity->getStage()?->getUuid();189+if ($stageId === null) {190+return null; // No stage, let ES handle191+ }192+193+return $filter->getFilterValue() === $stageId ? null : false;194+ }195+196+private function checkStartDate(Activity $activity, SearchFilter $filter): ?bool197+ {198+$startTime = $activity->getActualStartTime();199+if ($startTime === null) {200+return null;201+ }202+203+$filterDate = Carbon::parse($filter->getFilterValue());204+205+return $startTime->gte($filterDate) ? null : false;206+ }207+208+private function checkEndDate(Activity $activity, SearchFilter $filter): ?bool209+ {210+$endTime = $activity->getActualEndTime();211+if ($endTime === null) {212+return null;213+ }214+215+$filterDate = Carbon::parse($filter->getFilterValue())->endOfDay();216+217+return $endTime->lte($filterDate) ? null : false;218+ }219+220+private function checkLanguages(Activity $activity, SearchFilter $filter): ?bool221+ {222+$activityLanguage = $activity->getLanguageCode();223+if ($activityLanguage === null) {224+return null;225+ }226+227+// Filter values are always base language codes (e.g., 'en', 'fr').228+// Extract base code from activity locale (e.g., en_GB -> en) to match ES query behavior.229+// See LanguageFilterDefinition::getQueries() which uses regex: $language . '_[a-z]{2}'230+$activityLangCode = explode('_', $activityLanguage)[0];231+$filterLanguage = $filter->getFilterValue();232+233+return $activityLangCode === $filterLanguage ? null : false;69 }234 }70}235}</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":21,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I’m on page “<tabTitle>Jy 20493 smart instant nudge pre filtering by niko</tabTitle>” with “<selection>@@ -4,16 +4,17 @@445namespace Jiminny\\Component\\Nudge\\Job;5namespace Jiminny\\Component\\Nudge\\Job;667+use Carbon\\Carbon;7use Illuminate\\Bus\\Queueable;8use Illuminate\\Bus\\Queueable;8use Illuminate\\Contracts\\Queue\\ShouldQueue;9use Illuminate\\Contracts\\Queue\\ShouldQueue;9-use Illuminate\\Database\\Eloquent\\Builder;10use Illuminate\\Foundation\\Bus\\Dispatchable;10use Illuminate\\Foundation\\Bus\\Dispatchable;11use Illuminate\\Queue\\InteractsWithQueue;11use Illuminate\\Queue\\InteractsWithQueue;12use Illuminate\\Queue\\SerializesModels;12use Illuminate\\Queue\\SerializesModels;13use Illuminate\\Support\\Facades\\Log;13use Illuminate\\Support\\Facades\\Log;14use Jiminny\\Component\\Queue\\Constants;14use Jiminny\\Component\\Queue\\Constants;15use Jiminny\\Models\\Activity;15use Jiminny\\Models\\Activity;16use Jiminny\\Models\\Activity\\Search;16use Jiminny\\Models\\Activity\\Search;17+use Jiminny\\Models\\Activity\\SearchFilter;17use Jiminny\\Models\\Nudge;18use Jiminny\\Models\\Nudge;18use Jiminny\\Models\\Team;19use Jiminny\\Models\\Team;1920@@ -34,37 +35,201 @@343535public function handle(): void36public function handle(): void36 {37 {37-/** @var Activity $activity */38+$activity = Activity::with(['user.group'])->uuid($this->activityUuid, false)->firstOrFail();38-$activity = Activity::with(['user'])->uuid($this->activityUuid, false)->firstOrFail();39-40-/** @var Team $team */41$team = Team::with(['users'])->findOrFail($activity->user->team_id);39$team = Team::with(['users'])->findOrFail($activity->user->team_id);424043- Log::info(__METHOD__ . " Running for team $team->id.", [44-'activity_id' => $activity->id,45-'activity_uuid' => $this->activityUuid,46-'team_id' => $team->id,47- ]);48-49$usersIds = $team->users->pluck('id')->toArray();41$usersIds = $team->users->pluck('id')->toArray();504251-$searchesWithImmediateNudges = Activity\\Search::with(['nudges'])43+$searchesWithImmediateNudges = Activity\\Search::with([44+'nudges' => fn ($q) => $q->where('frequency', Nudge::FREQ_INSTANTLY),45+'filters',46+ ])52 ->whereIn('user_id', $usersIds)47 ->whereIn('user_id', $usersIds)53- ->whereHas('nudges', function (Builder $query) {48+ ->whereHas('nudges', fn ($q) => $q->where('frequency', Nudge::FREQ_INSTANTLY))54-$query->where('frequency', Nudge::FREQ_INSTANTLY);49+ ->get();55- })->get();50+51+$totalSearches = $searchesWithImmediateNudges->count();52+$skippedCount = 0;53+54+$searchesWithImmediateNudges->each(function (Search $search) use ($activity, &$skippedCount): void {55+$matchResult = $this->activityMightMatchSearch($activity, $search);565657-$searchesWithImmediateNudges->each(function (Search $search): void {57+if (! $matchResult['matches']) {58-$search->nudges->each(function (Nudge $nudge): void {58+$skippedCount++;59-// Filter only nudges that are set to be sent instantly59+ Log::info('Pre-filter skipped nudge dispatch', [60-if ($nudge->frequency === Nudge::FREQ_INSTANTLY) {60+'activity_uuid' => $activity->getUuid(),61- Log::info("Dispatching ProcessNudgeSearchJob for nudge $nudge->id.");61+'search_id' => $search->getId(),62+'mismatched_filter' => $matchResult['mismatch_reason'],63+'filter_value' => $matchResult['filter_value'],64+ ]);626563- ProcessNudgeSearchJob::dispatch($nudge);66+return;67+ }646865- Log::info("ProcessNudgeSearchJob dispatched for nudge $nudge->id.");69+$search->nudges->each(fn ($nudge) => ProcessNudgeSearchJob::dispatch($nudge));66- }67- });68 });70 });71+72+if ($totalSearches > 0) {73+ Log::info('Nudge pre-filter results', [74+'activity_uuid' => $activity->getUuid(),75+'total_searches' => $totalSearches,76+'skipped' => $skippedCount,77+'dispatched' => $totalSearches - $skippedCount,78+'skip_rate' => round(($skippedCount / $totalSearches) * 100, 2) . '%',79+ ]);80+ }81+ }82+83+private function activityMightMatchSearch(Activity $activity, Search $search): array84+ {85+foreach ($search->filters as $filter) {86+$filterName = $filter->getFilterProperty();87+88+$result = match ($filterName) {89+'group_id' => $this->checkGroupId($activity, $filter),90+'user_id' => $this->checkUserId($activity, $filter),91+'channel_id' => $this->checkChannelId($activity, $filter),92+'provider_id' => $this->checkProviderId($activity, $filter),93+'category_id' => $this->checkCategoryId($activity, $filter),94+'min_duration' => $this->checkMinDuration($activity, $filter),95+'max_duration' => $this->checkMaxDuration($activity, $filter),96+'not_logged' => $this->checkNotLogged($activity, $filter),97+'only_recorded' => $this->checkOnlyRecorded($activity, $filter),98+'languages' => $this->checkLanguages($activity, $filter),99+'stage_id' => $this->checkStageId($activity, $filter),100+'start_date' => $this->checkStartDate($activity, $filter),101+'end_date' => $this->checkEndDate($activity, $filter),102+default => null, // Unknown filter - can't pre-check, assume might match103+ };104+105+if ($result === false) {106+return [107+'matches' => false,108+'mismatch_reason' => $filterName,109+'filter_value' => $filter->getFilterValue(),110+ ];111+ }112+ }113+114+return ['matches' => true];115+ }116+117+private function checkGroupId(Activity $activity, SearchFilter $filter): ?bool118+ {119+$groupUuid = $activity->user->getGroup()?->getUuid();120+if ($groupUuid === null) {121+return null;122+ }123+124+return $filter->getFilterValue() === $groupUuid ? null : false;125+ }126+127+private function checkUserId(Activity $activity, SearchFilter $filter): ?bool128+ {129+return $filter->getFilterValue() === $activity->user->getUuid() ? null : false;130+ }131+132+private function checkChannelId(Activity $activity, SearchFilter $filter): ?bool133+ {134+return $filter->getFilterValue() === $activity->getType() ? null : false;135+ }136+137+private function checkProviderId(Activity $activity, SearchFilter $filter): ?bool138+ {139+return $filter->getFilterValue() === $activity->getProvider() ? null : false;140+ }141+142+private function checkCategoryId(Activity $activity, SearchFilter $filter): ?bool143+ {144+$categoryId = $activity->getCategory()?->getUuid();145+if ($categoryId === null) {146+return null;147+ }148+149+return $filter->getFilterValue() === $categoryId ? null : false;150+ }151+152+private function checkMinDuration(Activity $activity, SearchFilter $filter): ?bool153+ {154+return $activity->getDuration() >= (float) $filter->getFilterValue() ? null : false;155+ }156+157+private function checkMaxDuration(Activity $activity, SearchFilter $filter): ?bool158+ {159+return $activity->getDuration() <= (float) $filter->getFilterValue() ? null : false;160+ }161+162+private function checkNotLogged(Activity $activity, SearchFilter $filter): ?bool163+ {164+if (! $filter->getFilterValue()) {165+return null;166+ }167+168+$isLogged = $activity->getCrmProviderId() !== null;169+$isInternal = $activity->isInternal();170+171+return (! $isLogged || $isInternal) ? null : false;172+ }173+174+private function checkOnlyRecorded(Activity $activity, SearchFilter $filter): ?bool175+ {176+$filterValue = (int) $filter->getFilterValue();177+$hasRecording = $activity->recording_state !== Activity::RECORDING_OFF;178+179+return match ($filterValue) {180+1 => $hasRecording ? null : false, // Only recorded181+2 => ! $hasRecording ? null : false, // Only non-recorded182+default => null,183+ };184+ }185+186+private function checkStageId(Activity $activity, SearchFilter $filter): ?bool187+ {188+$stageId = $activity->getStage()?->getUuid();189+if ($stageId === null) {190+return null; // No stage, let ES handle191+ }192+193+return $filter->getFilterValue() === $stageId ? null : false;194+ }195+196+private function checkStartDate(Activity $activity, SearchFilter $filter): ?bool197+ {198+$startTime = $activity->getActualStartTime();199+if ($startTime === null) {200+return null;201+ }202+203+$filterDate = Carbon::parse($filter->getFilterValue());204+205+return $startTime->gte($filterDate) ? null : false;206+ }207+208+private function checkEndDate(Activity $activity, SearchFilter $filter): ?bool209+ {210+$endTime = $activity->getActualEndTime();211+if ($endTime === null) {212+return null;213+ }214+215+$filterDate = Carbon::parse($filter->getFilterValue())->endOfDay();216+217+return $endTime->lte($filterDate) ? null : false;218+ }219+220+private function checkLanguages(Activity $activity, SearchFilter $filter): ?bool221+ {222+$activityLanguage = $activity->getLanguageCode();223+if ($activityLanguage === null) {224+return null;225+ }226+227+// Filter values are always base language codes (e.g., 'en', 'fr').228+// Extract base code from activity locale (e.g., en_GB -> en) to match ES query behavior.229+// See LanguageFilterDefinition::getQueries() which uses regex: $language . '_[a-z]{2}'230+$activityLangCode = explode('_', $activityLanguage)[0];231+$filterLanguage = $filter->getFilterValue();232+233+return $activityLangCode === $filterLanguage ? null : false;69 }234 }70}235}</selection>” selected.","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Expand","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Listen","depth":22,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Gemini said","depth":20,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"This code selection introduces a","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"pre-filtering mechanism","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to the","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Jiminny\\Component\\Nudge\\Job","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"namespace. The primary goal is to optimize performance by validating an activity against search criteria in-memory before dispatching costly background jobs.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Core Functionality Changes","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Core Functionality Changes","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Selective Loading:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"handle()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"method now eager-loads","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"user.group","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"for activities and specifically filters for","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"FREQ_INSTANTLY","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"nudges and their associated search filters.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Pre-Dispatch Validation:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Instead of dispatching jobs for every instant nudge, the system now calls","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"activityMightMatchSearch()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Short-Circuiting:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If an activity fails a pre-filter check (e.g., mismatched user ID or duration), the job dispatch is skipped, and the event is logged with the specific mismatch reason.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Performance Metrics:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Adds summary logging at the end of the process to track:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Total searches processed.","depth":28,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Number of skipped dispatches.","depth":28,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The \"Skip Rate\" percentage.","depth":28,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Implemented Filter Checks","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Implemented Filter Checks","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The logic includes a","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"match","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"expression to validate various activity attributes against","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SearchFilter","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"values:","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Identity & Metadata:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Matches for","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"group_id","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"user_id","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"channel_id","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", and","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"provider_id","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Temporal & Duration:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* Validates","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"min_duration","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"max_duration","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Checks","depth":28,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"start_date","depth":29,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and","depth":28,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"end_date","depth":29,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"using Carbon parsing.","depth":28,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Activity State:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Logging:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Determines if an activity is logged to a CRM or is internal via","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"checkNotLogged","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Recording:","depth":28,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Uses","depth":28,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"checkOnlyRecorded","depth":29,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to filter based on whether a recording exists.","depth":28,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Categorization:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Checks for","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"category_id","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"stage_id","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", and","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"languages","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Note:","depth":28,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The language check specifically extracts base codes (e.g.,","depth":28,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"en","depth":29,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"from","depth":28,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"en_GB","depth":29,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") to align with Elasticsearch behavior.","depth":28,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Logic Design","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Logic Design","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Nullable Returns:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Filter methods return","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"null","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"if a match is possible (or cannot be determined), and","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"false","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"only when a definitive mismatch is found.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Safe Fallback:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If a filter type is unknown (","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"default","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"), the system assumes a match and proceeds to dispatch, ensuring no false negatives.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Good response","depth":22,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bad response","depth":22,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Share & export","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy","depth":22,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said what is the logic behind diff. Act as code reviewer. First review the changes then explain it and then evaluate. Try to find potential issues and bottlenecks","depth":21,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"what is the logic behind diff. Act as code reviewer. First review the changes then explain it and then evaluate. Try to find potential issues and bottlenecks","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Expand","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Listen","depth":22,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":20,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Show thinking","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Gemini said","depth":20,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Here is a review of the changes provided in the diff, broken down by your requested structure.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"1. Review of Changes","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1. Review of Changes","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"This PR refactors the","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ProcessNudgeSearchJob","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"dispatching mechanism within the","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"handle()","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"method.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Query Optimization:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Eager loads necessary relationships (","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"user.group","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"filters","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") and scopes the","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"nudges","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"relationship at the database level to only fetch","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"FREQ_INSTANTLY","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"records.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"In-Memory Filtering:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Introduces a pre-filtering mechanism (","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"activityMightMatchSearch","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") that checks the","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Activity","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"against","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SearchFilter","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"criteria before deciding to dispatch a job.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Helper Methods:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Adds 13 private","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"check*","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"methods to handle the specific comparison logic for different filter types (e.g., duration, dates, categories, stages).","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Observability:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Adds structured logging to record exactly why a nudge was skipped and outputs a summary report (total, skipped, dispatched, skip rate) at the end of the execution.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"2. Explanation of Logic","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2. Explanation of Logic","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The core philosophy of this change is","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"veto-based short-circuiting\"","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Previously, the job fetched all searches with instant nudges for a team's users and blindly dispatched a queue job for every single one. The heavy lifting of deciding if the activity actually matched the search was likely deferred to the queue worker and Elasticsearch.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Now, the code evaluates the filters in the current process:","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"It iterates through each","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Search","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and its associated","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SearchFilter","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"s.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"It routes the filter to a specific","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"check*","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"method using a","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"match","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"expression based on the filter's property name.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Veto:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"check*","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"methods are designed to return","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"false","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"only if there is an absolute mismatch","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(e.g., the filter requires a minimum duration of 10, but the activity is 5).","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Pass:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If the filter matches, or if the activity lacks the data needed to make a firm decision (e.g., no stage is assigned, or the filter type is unrecognized), the method returns","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"null","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":". This acts as a pass, delegating the final strict evaluation to Elasticsearch later in the pipeline.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If any filter returns","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"false","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", the search is skipped, saving a queue dispatch.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"3. Evaluation","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3. Evaluation","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Overall, this is a","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"highly effective performance optimization","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Pros:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"It significantly reduces queue bloat. By filtering out obvious mismatches in-memory, you save the overhead of serializing, dispatching, picking up, and processing jobs that are destined to fail or do nothing. The use of","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"match","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"makes the routing exceptionally clean, and the nullable return design is a smart way to avoid false negatives.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Cons/Trade-offs:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You are trading background queue worker time for a slight increase in synchronous memory and CPU usage on the current job. However, queue I/O is almost always more expensive than simple in-memory comparisons, making this a worthwhile trade.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"4. Potential Issues & Bottlenecks","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"4. Potential Issues & Bottlenecks","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"While the logic is sound, there are a few architectural bottlenecks and risks introduced or maintained in this diff:","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Potential N+1 Query / Lazy Loading Issues:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"In the","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"handle","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"method, the activity is loaded with","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Activity::with(['user.group'])","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":". However, inside your new","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"check*","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"methods, you are calling:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$activity->getCategory()?->getUuid()","depth":29,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$activity->getStage()?->getUuid()","depth":29,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If","depth":28,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"category","depth":29,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and","depth":28,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"stage","depth":29,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"are Eloquent relationships and are not eager-loaded on the original","depth":28,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$activity","depth":29,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"model, calling these methods inside a loop of","depth":28,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$totalSearches","depth":29,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"will trigger lazy-loaded database queries.","depth":28,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Fix:","depth":28,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Update line 38 to:","depth":28,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$activity = Activity::with(['user.group', 'category', 'stage'])->...","depth":29,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Massive Memory Consumption (Pre-existing but critical):","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Lines 39-41:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"PHP","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Download code","depth":27,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy code","depth":27,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"$team","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"= Team::with([","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'users'","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"])->findOrFail(","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$activity","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"->user->team_id);","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$usersIds","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"=","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$team","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"->users->pluck(","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'id'","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")->toArray();","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If a team has thousands of users,","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Team::with(['users'])","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"hydrates thousands of full Eloquent User models into memory just to extract their IDs.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Fix:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bypass hydrating the models entirely by querying the relationship directly:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$usersIds = $team->users()->pluck('id')->toArray();","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Repeated Carbon Parsing in Loops:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"In","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"checkStartDate","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"checkEndDate","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", you parse the filter date:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Carbon::parse($filter->getFilterValue())","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":". If the same date filter applies to multiple searches, Carbon is being instantiated repeatedly in the loop. While Carbon is relatively fast, doing this hundreds of times adds unnecessary CPU cycles.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Fix:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"This is a minor nitpick, but if performance is the absolute goal, you could memoize/cache the parsed filter values within the job.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Loose Type Comparisons:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"In methods like","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"checkChannelId","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"or","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"checkLanguages","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", you are using strict equality (","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"===","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"). Ensure that","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$filter->getFilterValue()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(which is typically returned as a string from a database payload) matches the exact type returned by","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$activity->getType()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"or","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$activityLangCode","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":". If one is an integer","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and the other is a string","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"1\"","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", the strict check will return","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"false","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", incorrectly preventing the nudge from sending.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Good response","depth":22,"bounds":{"left":0.3332779,"top":0.0,"width":0.010638298,"height":0.025538707},"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bad response","depth":22,"bounds":{"left":0.34391624,"top":0.0,"width":0.010638298,"height":0.025538707},"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Share & export","depth":21,"bounds":{"left":0.35455453,"top":0.0,"width":0.010638298,"height":0.025538707},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy","depth":22,"bounds":{"left":0.36519283,"top":0.0,"width":0.010638298,"height":0.025538707},"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":21,"bounds":{"left":0.37583113,"top":0.0,"width":0.010638298,"height":0.025538707},"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":21,"bounds":{"left":0.3492354,"top":0.0,"width":0.013297873,"height":0.031923383},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Edit","depth":21,"bounds":{"left":0.36386302,"top":0.0,"width":0.013297873,"height":0.031923383},"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said what would be your suggestion?","depth":21,"bounds":{"left":0.38380983,"top":0.0,"width":0.065159574,"height":0.03830806},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"bounds":{"left":0.32629654,"top":0.0,"width":0.019946808,"height":0.016360734},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"what would be your suggestion?","depth":23,"bounds":{"left":0.38380983,"top":0.0,"width":0.04720745,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Listen","depth":22,"bounds":{"left":0.4409907,"top":0.05586592,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":20,"bounds":{"left":0.4409907,"top":0.05027933,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Show thinking","depth":25,"bounds":{"left":0.34990028,"top":0.058260176,"width":0.030917553,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Gemini said","depth":20,"bounds":{"left":0.34757313,"top":0.09976058,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":21,"bounds":{"left":0.34757313,"top":0.10175578,"width":0.04105718,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Here are actionable suggestions to address the potential issues and bottlenecks identified in the review. These optimizations focus on reducing memory footprint, preventing lazy-loading, and ensuring data type resilience.","depth":24,"bounds":{"left":0.3366024,"top":0.10295291,"width":0.11502659,"height":0.09936153},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"1. Fix the N+1 Query Risk (Eager Loading)","depth":23,"bounds":{"left":0.3366024,"top":0.22665602,"width":0.11502659,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1. Fix the N+1 Query Risk (Eager Loading)","depth":24,"bounds":{"left":0.3366024,"top":0.22825219,"width":0.10555186,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Your","depth":24,"bounds":{"left":0.3366024,"top":0.254589,"width":0.011968086,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"checkCategoryId","depth":25,"bounds":{"left":0.35056517,"top":0.25578612,"width":0.041888297,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and","depth":24,"bounds":{"left":0.39444813,"top":0.254589,"width":0.011968086,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"checkStageId","depth":25,"bounds":{"left":0.4084109,"top":0.25578612,"width":0.033410903,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"methods call","depth":24,"bounds":{"left":0.3366024,"top":0.254589,"width":0.1087101,"height":0.037110932},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$activity->getCategory()","depth":25,"bounds":{"left":0.37084442,"top":0.27653632,"width":0.06698803,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and","depth":24,"bounds":{"left":0.4398271,"top":0.2753392,"width":0.011801862,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$activity->getStage()","depth":25,"bounds":{"left":0.3385971,"top":0.2972865,"width":0.05867686,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":". If these relationships aren't eager-loaded, Laravel will execute a new database query for every check inside the loop.","depth":24,"bounds":{"left":0.3366024,"top":0.29608938,"width":0.1143617,"height":0.07861133},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Suggestion:","depth":24,"bounds":{"left":0.3366024,"top":0.38786912,"width":0.030585106,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Add","depth":24,"bounds":{"left":0.3671875,"top":0.38786912,"width":0.012300532,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"category","depth":25,"bounds":{"left":0.38148272,"top":0.38906625,"width":0.02244016,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and","depth":24,"bounds":{"left":0.40591756,"top":0.38786912,"width":0.011801862,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"stage","depth":25,"bounds":{"left":0.4197141,"top":0.38906625,"width":0.013962766,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to the initial eager-load array.","depth":24,"bounds":{"left":0.3366024,"top":0.38786912,"width":0.11502659,"height":0.037110932},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"PHP","depth":25,"bounds":{"left":0.34192154,"top":0.4517159,"width":0.009142287,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Download code","depth":25,"bounds":{"left":0.42237368,"top":0.44293696,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy code","depth":25,"bounds":{"left":0.43567154,"top":0.44293696,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"// Before (Line 38)","depth":25,"bounds":{"left":0.34192154,"top":0.49361533,"width":0.053025264,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$activity","depth":25,"bounds":{"left":0.34192154,"top":0.5103751,"width":0.025099734,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"= Activity::with([","depth":25,"bounds":{"left":0.36702126,"top":0.5103751,"width":0.053025264,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'user.group'","depth":25,"bounds":{"left":0.42004654,"top":0.5103751,"width":0.03357713,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"])->uuid(","depth":25,"bounds":{"left":0.45362368,"top":0.5103751,"width":0.025099734,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this","depth":25,"bounds":{"left":0.4787234,"top":0.5103751,"width":0.013962766,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"->activityUuid,","depth":25,"bounds":{"left":0.49268618,"top":0.5103751,"width":0.044714097,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"false","depth":25,"bounds":{"left":0.53740025,"top":0.5103751,"width":0.013962766,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")->firstOrFail();","depth":25,"bounds":{"left":0.55136305,"top":0.5103751,"width":0.047539894,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"// After","depth":25,"bounds":{"left":0.34192154,"top":0.54389465,"width":0.022273935,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$activity","depth":25,"bounds":{"left":0.34192154,"top":0.5606544,"width":0.025099734,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"= Activity::with([","depth":25,"bounds":{"left":0.36702126,"top":0.5606544,"width":0.053025264,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'user.group'","depth":25,"bounds":{"left":0.42004654,"top":0.5606544,"width":0.03357713,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":25,"bounds":{"left":0.45362368,"top":0.5606544,"width":0.0056515955,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'category'","depth":25,"bounds":{"left":0.45927528,"top":0.5606544,"width":0.027925532,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":25,"bounds":{"left":0.4872008,"top":0.5606544,"width":0.005485372,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'stage'","depth":25,"bounds":{"left":0.49268618,"top":0.5606544,"width":0.019614361,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"])->uuid(","depth":25,"bounds":{"left":0.51230055,"top":0.5606544,"width":0.025099734,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this","depth":25,"bounds":{"left":0.53740025,"top":0.5606544,"width":0.013962766,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"->activityUuid,","depth":25,"bounds":{"left":0.55136305,"top":0.5606544,"width":0.044714097,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"false","depth":25,"bounds":{"left":0.59607714,"top":0.5606544,"width":0.013962766,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")->firstOrFail();","depth":25,"bounds":{"left":0.6100399,"top":0.5606544,"width":0.04737367,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"2. Drastically Reduce Memory Usage","depth":23,"bounds":{"left":0.3366024,"top":0.6113328,"width":0.11502659,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2. Drastically Reduce Memory Usage","depth":24,"bounds":{"left":0.3366024,"top":0.612929,"width":0.094913565,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Currently, you are hydrating full Eloquent","depth":24,"bounds":{"left":0.3366024,"top":0.6392658,"width":0.099567816,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"User","depth":25,"bounds":{"left":0.4381649,"top":0.6404629,"width":0.011136968,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"models into memory just to extract their IDs. If a team has hundreds or thousands of users, this will spike memory usage and potentially crash the worker.","depth":24,"bounds":{"left":0.3366024,"top":0.6392658,"width":0.11502659,"height":0.09936153},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Suggestion:","depth":24,"bounds":{"left":0.3366024,"top":0.7517957,"width":0.030585106,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Use the relationship query builder to perform the","depth":24,"bounds":{"left":0.3366024,"top":0.7517957,"width":0.11486037,"height":0.037110932},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"pluck","depth":25,"bounds":{"left":0.37516624,"top":0.77374303,"width":0.013962766,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"directly at the database level, bypassing Eloquent model hydration entirely.","depth":24,"bounds":{"left":0.3366024,"top":0.7725459,"width":0.11486037,"height":0.057861134},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"PHP","depth":25,"bounds":{"left":0.34192154,"top":0.85714287,"width":0.009142287,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Download code","depth":25,"bounds":{"left":0.42237368,"top":0.84836394,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy code","depth":25,"bounds":{"left":0.43567154,"top":0.84836394,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"// Before (Lines 39-41)","depth":25,"bounds":{"left":0.34192154,"top":0.8990423,"width":0.06416223,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$team","depth":25,"bounds":{"left":0.34192154,"top":0.91580206,"width":0.013962766,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"= Team::with([","depth":25,"bounds":{"left":0.3558843,"top":0.91580206,"width":0.041888297,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'users'","depth":25,"bounds":{"left":0.3977726,"top":0.91580206,"width":0.019614361,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"])->findOrFail(","depth":25,"bounds":{"left":0.41738698,"top":0.91580206,"width":0.041888297,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$activity","depth":25,"bounds":{"left":0.45927528,"top":0.91580206,"width":0.025099734,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"->user->team_id);","depth":25,"bounds":{"left":0.484375,"top":0.91580206,"width":0.04737367,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$usersIds","depth":25,"bounds":{"left":0.34192154,"top":0.9325619,"width":0.025099734,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"=","depth":25,"bounds":{"left":0.36702126,"top":0.9325619,"width":0.008477394,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$team","depth":25,"bounds":{"left":0.37549868,"top":0.9325619,"width":0.013962766,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"->users->pluck(","depth":25,"bounds":{"left":0.38946143,"top":0.9325619,"width":0.041888297,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'id'","depth":25,"bounds":{"left":0.43134972,"top":0.9325619,"width":0.011136968,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")->toArray();","depth":25,"bounds":{"left":0.4424867,"top":0.9325619,"width":0.036236703,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"// After (No need to eager load 'users' on the Team model anymore)","depth":25,"bounds":{"left":0.34192154,"top":0.9660814,"width":0.18434176,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$team","depth":25,"bounds":{"left":0.34192154,"top":0.9828412,"width":0.013962766,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"= Team::findOrFail(","depth":25,"bounds":{"left":0.3558843,"top":0.9828412,"width":0.055851065,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$activity","depth":25,"bounds":{"left":0.4117354,"top":0.9828412,"width":0.025099734,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"->user->team_id);","depth":25,"bounds":{"left":0.4368351,"top":0.9828412,"width":0.047539894,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$usersIds","depth":25,"bounds":{"left":0.34192154,"top":0.99960095,"width":0.025099734,"height":0.0003990531},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"=","depth":25,"bounds":{"left":0.36702126,"top":0.99960095,"width":0.008477394,"height":0.0003990531},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$team","depth":25,"bounds":{"left":0.37549868,"top":0.99960095,"width":0.013962766,"height":0.0003990531},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"->users()->pluck(","depth":25,"bounds":{"left":0.38946143,"top":0.99960095,"width":0.04737367,"height":0.0003990531},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'users.id'","depth":25,"bounds":{"left":0.4368351,"top":0.99960095,"width":0.027925532,"height":0.0003990531},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")->toArray();","depth":25,"bounds":{"left":0.46476063,"top":0.99960095,"width":0.0390625,"height":0.0003990531},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"// Note the `()` after users","depth":25,"bounds":{"left":0.50382316,"top":0.99960095,"width":0.07829122,"height":0.0003990531},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"3. Harden Type Comparisons","depth":23,"bounds":{"left":0.3366024,"top":1.0,"width":0.11502659,"height":-0.05027938},"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3. Harden Type Comparisons","depth":24,"bounds":{"left":0.3366024,"top":1.0,"width":0.07396942,"height":-0.051875472},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Since Elasticsearch and databases often return IDs or filter values as strings, strict comparison (","depth":24,"bounds":{"left":0.3366024,"top":1.0,"width":0.11502659,"height":-0.07821226},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"===","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") against an Eloquent model's attribute (which might be cast to an integer) can cause false negatives.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Suggestion:","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Cast your values before comparison, or use loose equality (","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"==","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") if you are absolutely certain of the payload structure.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"PHP","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Download code","depth":25,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy code","depth":25,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"// Example for checkChannelId (Lines 132-135)","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"function","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
8676700174437749351
|
6059967888930249027
|
click
|
accessibility
|
NULL
|
Platform Sprint 3 Q2 - Platform Team - Scrum Board Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
SevenShores\Hubspot\Exceptions\BadRequest: Client error: `POST [URL_WITH_CREDENTIALS] -4,16 +4,17 @@445namespace Jiminny\Component\Nudge\Job;5namespace Jiminny\Component\Nudge\Job;667+use Carbon\Carbon;7use Illuminate\Bus\Queueable;8use Illuminate\Bus\Queueable;8use Illuminate\Contracts\Queue\ShouldQueue;9use Illuminate\Contracts\Queue\ShouldQueue;9-use Illuminate\Database\Eloquent\Builder;10use Illuminate\Foundation\Bus\Dispatchable;10use Illuminate\Foundation\Bus\Dispatchable;11use Illuminate\Queue\InteractsWithQueue;11use Illuminate\Queue\InteractsWithQueue;12use Illuminate\Queue\SerializesModels;12use Illuminate\Queue\SerializesModels;13use Illuminate\Support\Facades\Log;13use Illuminate\Support\Facades\Log;14use Jiminny\Component\Queue\Constants;14use Jiminny\Component\Queue\Constants;15use Jiminny\Models\Activity;15use Jiminny\Models\Activity;16use Jiminny\Models\Activity\Search;16use Jiminny\Models\Activity\Search;17+use Jiminny\Models\Activity\SearchFilter;17use Jiminny\Models\Nudge;18use Jiminny\Models\Nudge;18use Jiminny\Models\Team;19use Jiminny\Models\Team;1920@@ -34,37 +35,201 @@343535public function handle(): void36public function handle(): void36 {37 {37-/** @var Activity $activity */38+$activity = Activity::with(['user.group'])->uuid($this->activityUuid, false)->firstOrFail();38-$activity = Activity::with(['user'])->uuid($this->activityUuid, false)->firstOrFail();39-40-/** @var Team $team */41$team = Team::with(['users'])->findOrFail($activity->user->team_id);39$team = Team::with(['users'])->findOrFail($activity->user->team_id);424043- Log::info(__METHOD__ . " Running for team $team->id.", [44-'activity_id' => $activity->id,45-'activity_uuid' => $this->activityUuid,46-'team_id' => $team->id,47- ]);48-49$usersIds = $team->users->pluck('id')->toArray();41$usersIds = $team->users->pluck('id')->toArray();504251-$searchesWithImmediateNudges = Activity\Search::with(['nudges'])43+$searchesWithImmediateNudges = Activity\Search::with([44+'nudges' => fn ($q) => $q->where('frequency', Nudge::FREQ_INSTANTLY),45+'filters',46+ ])52 ->whereIn('user_id', $usersIds)47 ->whereIn('user_id', $usersIds)53- ->whereHas('nudges', function (Builder $query) {48+ ->whereHas('nudges', fn ($q) => $q->where('frequency', Nudge::FREQ_INSTANTLY))54-$query->where('frequency', Nudge::FREQ_INSTANTLY);49+ ->get();55- })->get();50+51+$totalSearches = $searchesWithImmediateNudges->count();52+$skippedCount = 0;53+54+$searchesWithImmediateNudges->each(function (Search $search) use ($activity, &$skippedCount): void {55+$matchResult = $this->activityMightMatchSearch($activity, $search);565657-$searchesWithImmediateNudges->each(function (Search $search): void {57+if (! $matchResult['matches']) {58-$search->nudges->each(function (Nudge $nudge): void {58+$skippedCount++;59-// Filter only nudges that are set to be sent instantly59+ Log::info('Pre-filter skipped nudge dispatch', [60-if ($nudge->frequency === Nudge::FREQ_INSTANTLY) {60+'activity_uuid' => $activity->getUuid(),61- Log::info("Dispatching ProcessNudgeSearchJob for nudge $nudge->id.");61+'search_id' => $search->getId(),62+'mismatched_filter' => $matchResult['mismatch_reason'],63+'filter_value' => $matchResult['filter_value'],64+ ]);626563- ProcessNudgeSearchJob::dispatch($nudge);66+return;67+ }646865- Log::info("ProcessNudgeSearchJob dispatched for nudge $nudge->id.");69+$search->nudges->each(fn ($nudge) => ProcessNudgeSearchJob::dispatch($nudge));66- }67- });68 });70 });71+72+if ($totalSearches > 0) {73+ Log::info('Nudge pre-filter results', [74+'activity_uuid' => $activity->getUuid(),75+'total_searches' => $totalSearches,76+'skipped' => $skippedCount,77+'dispatched' => $totalSearches - $skippedCount,78+'skip_rate' => round(($skippedCount / $totalSearches) * 100, 2) . '%',79+ ]);80+ }81+ }82+83+private function activityMightMatchSearch(Activity $activity, Search $search): array84+ {85+foreach ($search->filters as $filter) {86+$filterName = $filter->getFilterProperty();87+88+$result = match ($filterName) {89+'group_id' => $this->checkGroupId($activity, $filter),90+'user_id' => $this->checkUserId($activity, $filter),91+'channel_id' => $this->checkChannelId($activity, $filter),92+'provider_id' => $this->checkProviderId($activity, $filter),93+'category_id' => $this->checkCategoryId($activity, $filter),94+'min_duration' => $this->checkMinDuration($activity, $filter),95+'max_duration' => $this->checkMaxDuration($activity, $filter),96+'not_logged' => $this->checkNotLogged($activity, $filter),97+'only_recorded' => $this->checkOnlyRecorded($activity, $filter),98+'languages' => $this->checkLanguages($activity, $filter),99+'stage_id' => $this->checkStageId($activity, $filter),100+'start_date' => $this->checkStartDate($activity, $filter),101+'end_date' => $this->checkEndDate($activity, $filter),102+default => null, // Unknown filter - can't pre-check, assume might match103+ };104+105+if ($result === false) {106+return [107+'matches' => false,108+'mismatch_reason' => $filterName,109+'filter_value' => $filter->getFilterValue(),110+ ];111+ }112+ }113+114+return ['matches' => true];115+ }116+117+private function checkGroupId(Activity $activity, SearchFilter $filter): ?bool118+ {119+$groupUuid = $activity->user->getGroup()?->getUuid();120+if ($groupUuid === null) {121+return null;122+ }123+124+return $filter->getFilterValue() === $groupUuid ? null : false;125+ }126+127+private function checkUserId(Activity $activity, SearchFilter $filter): ?bool128+ {129+return $filter->getFilterValue() === $activity->user->getUuid() ? null : false;130+ }131+132+private function checkChannelId(Activity $activity, SearchFilter $filter): ?bool133+ {134+return $filter->getFilterValue() === $activity->getType() ? null : false;135+ }136+137+private function checkProviderId(Activity $activity, SearchFilter $filter): ?bool138+ {139+return $filter->getFilterValue() === $activity->getProvider() ? null : false;140+ }141+142+private function checkCategoryId(Activity $activity, SearchFilter $filter): ?bool143+ {144+$categoryId = $activity->getCategory()?->getUuid();145+if ($categoryId === null) {146+return null;147+ }148+149+return $filter->getFilterValue() === $categoryId ? null : false;150+ }151+152+private function checkMinDuration(Activity $activity, SearchFilter $filter): ?bool153+ {154+return $activity->getDuration() >= (float) $filter->getFilterValue() ? null : false;155+ }156+157+private function checkMaxDuration(Activity $activity, SearchFilter $filter): ?bool158+ {159+return $activity->getDuration() <= (float) $filter->getFilterValue() ? null : false;160+ }161+162+private function checkNotLogged(Activity $activity, SearchFilter $filter): ?bool163+ {164+if (! $filter->getFilterValue()) {165+return null;166+ }167+168+$isLogged = $activity->getCrmProviderId() !== null;169+$isInternal = $activity->isInternal();170+171+return (! $isLogged || $isInternal) ? null : false;172+ }173+174+private function checkOnlyRecorded(Activity $activity, SearchFilter $filter): ?bool175+ {176+$filterValue = (int) $filter->getFilterValue();177+$hasRecording = $activity->recording_state !== Activity::RECORDING_OFF;178+179+return match ($filterValue) {180+1 => $hasRecording ? null : false, // Only recorded181+2 => ! $hasRecording ? null : false, // Only non-recorded182+default => null,183+ };184+ }185+186+private function checkStageId(Activity $activity, SearchFilter $filter): ?bool187+ {188+$stageId = $activity->getStage()?->getUuid();189+if ($stageId === null) {190+return null; // No stage, let ES handle191+ }192+193+return $filter->getFilterValue() === $stageId ? null : false;194+ }195+196+private function checkStartDate(Activity $activity, SearchFilter $filter): ?bool197+ {198+$startTime = $activity->getActualStartTime();199+if ($startTime === null) {200+return null;201+ }202+203+$filterDate = Carbon::parse($filter->getFilterValue());204+205+return $startTime->gte($filterDate) ? null : false;206+ }207+208+private function checkEndDate(Activity $activity, SearchFilter $filter): ?bool209+ {210+$endTime = $activity->getActualEndTime();211+if ($endTime === null) {212+return null;213+ }214+215+$filterDate = Carbon::parse($filter->getFilterValue())->endOfDay();216+217+return $endTime->lte($filterDate) ? null : false;218+ }219+220+private function checkLanguages(Activity $activity, SearchFilter $filter): ?bool221+ {222+$activityLanguage = $activity->getLanguageCode();223+if ($activityLanguage === null) {224+return null;225+ }226+227+// Filter values are always base language codes (e.g., 'en', 'fr').228+// Extract base code from activity locale (e.g., en_GB -> en) to match ES query behavior.229+// See LanguageFilterDefinition::getQueries() which uses regex: $language . '_[a-z]{2}'230+$activityLangCode = explode('_', $activityLanguage)[0];231+$filterLanguage = $filter->getFilterValue();232+233+return $activityLangCode === $filterLanguage ? null : false;69 }234 }70}235}</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>Jy 20493 smart instant nudge pre filtering by niko</tabTitle>” with “<selection>@@ -4,16 +4,17 @@445namespace Jiminny\Component\Nudge\Job;5namespace Jiminny\Component\Nudge\Job;667+use Carbon\Carbon;7use Illuminate\Bus\Queueable;8use Illuminate\Bus\Queueable;8use Illuminate\Contracts\Queue\ShouldQueue;9use Illuminate\Contracts\Queue\ShouldQueue;9-use Illuminate\Database\Eloquent\Builder;10use Illuminate\Foundation\Bus\Dispatchable;10use Illuminate\Foundation\Bus\Dispatchable;11use Illuminate\Queue\InteractsWithQueue;11use Illuminate\Queue\InteractsWithQueue;12use Illuminate\Queue\SerializesModels;12use Illuminate\Queue\SerializesModels;13use Illuminate\Support\Facades\Log;13use Illuminate\Support\Facades\Log;14use Jiminny\Component\Queue\Constants;14use Jiminny\Component\Queue\Constants;15use Jiminny\Models\Activity;15use Jiminny\Models\Activity;16use Jiminny\Models\Activity\Search;16use Jiminny\Models\Activity\Search;17+use Jiminny\Models\Activity\SearchFilter;17use Jiminny\Models\Nudge;18use Jiminny\Models\Nudge;18use Jiminny\Models\Team;19use Jiminny\Models\Team;1920@@ -34,37 +35,201 @@343535public function handle(): void36public function handle(): void36 {37 {37-/** @var Activity $activity */38+$activity = Activity::with(['user.group'])->uuid($this->activityUuid, false)->firstOrFail();38-$activity = Activity::with(['user'])->uuid($this->activityUuid, false)->firstOrFail();39-40-/** @var Team $team */41$team = Team::with(['users'])->findOrFail($activity->user->team_id);39$team = Team::with(['users'])->findOrFail($activity->user->team_id);424043- Log::info(__METHOD__ . " Running for team $team->id.", [44-'activity_id' => $activity->id,45-'activity_uuid' => $this->activityUuid,46-'team_id' => $team->id,47- ]);48-49$usersIds = $team->users->pluck('id')->toArray();41$usersIds = $team->users->pluck('id')->toArray();504251-$searchesWithImmediateNudges = Activity\Search::with(['nudges'])43+$searchesWithImmediateNudges = Activity\Search::with([44+'nudges' => fn ($q) => $q->where('frequency', Nudge::FREQ_INSTANTLY),45+'filters',46+ ])52 ->whereIn('user_id', $usersIds)47 ->whereIn('user_id', $usersIds)53- ->whereHas('nudges', function (Builder $query) {48+ ->whereHas('nudges', fn ($q) => $q->where('frequency', Nudge::FREQ_INSTANTLY))54-$query->where('frequency', Nudge::FREQ_INSTANTLY);49+ ->get();55- })->get();50+51+$totalSearches = $searchesWithImmediateNudges->count();52+$skippedCount = 0;53+54+$searchesWithImmediateNudges->each(function (Search $search) use ($activity, &$skippedCount): void {55+$matchResult = $this->activityMightMatchSearch($activity, $search);565657-$searchesWithImmediateNudges->each(function (Search $search): void {57+if (! $matchResult['matches']) {58-$search->nudges->each(function (Nudge $nudge): void {58+$skippedCount++;59-// Filter only nudges that are set to be sent instantly59+ Log::info('Pre-filter skipped nudge dispatch', [60-if ($nudge->frequency === Nudge::FREQ_INSTANTLY) {60+'activity_uuid' => $activity->getUuid(),61- Log::info("Dispatching ProcessNudgeSearchJob for nudge $nudge->id.");61+'search_id' => $search->getId(),62+'mismatched_filter' => $matchResult['mismatch_reason'],63+'filter_value' => $matchResult['filter_value'],64+ ]);626563- ProcessNudgeSearchJob::dispatch($nudge);66+return;67+ }646865- Log::info("ProcessNudgeSearchJob dispatched for nudge $nudge->id.");69+$search->nudges->each(fn ($nudge) => ProcessNudgeSearchJob::dispatch($nudge));66- }67- });68 });70 });71+72+if ($totalSearches > 0) {73+ Log::info('Nudge pre-filter results', [74+'activity_uuid' => $activity->getUuid(),75+'total_searches' => $totalSearches,76+'skipped' => $skippedCount,77+'dispatched' => $totalSearches - $skippedCount,78+'skip_rate' => round(($skippedCount / $totalSearches) * 100, 2) . '%',79+ ]);80+ }81+ }82+83+private function activityMightMatchSearch(Activity $activity, Search $search): array84+ {85+foreach ($search->filters as $filter) {86+$filterName = $filter->getFilterProperty();87+88+$result = match ($filterName) {89+'group_id' => $this->checkGroupId($activity, $filter),90+'user_id' => $this->checkUserId($activity, $filter),91+'channel_id' => $this->checkChannelId($activity, $filter),92+'provider_id' => $this->checkProviderId($activity, $filter),93+'category_id' => $this->checkCategoryId($activity, $filter),94+'min_duration' => $this->checkMinDuration($activity, $filter),95+'max_duration' => $this->checkMaxDuration($activity, $filter),96+'not_logged' => $this->checkNotLogged($activity, $filter),97+'only_recorded' => $this->checkOnlyRecorded($activity, $filter),98+'languages' => $this->checkLanguages($activity, $filter),99+'stage_id' => $this->checkStageId($activity, $filter),100+'start_date' => $this->checkStartDate($activity, $filter),101+'end_date' => $this->checkEndDate($activity, $filter),102+default => null, // Unknown filter - can't pre-check, assume might match103+ };104+105+if ($result === false) {106+return [107+'matches' => false,108+'mismatch_reason' => $filterName,109+'filter_value' => $filter->getFilterValue(),110+ ];111+ }112+ }113+114+return ['matches' => true];115+ }116+117+private function checkGroupId(Activity $activity, SearchFilter $filter): ?bool118+ {119+$groupUuid = $activity->user->getGroup()?->getUuid();120+if ($groupUuid === null) {121+return null;122+ }123+124+return $filter->getFilterValue() === $groupUuid ? null : false;125+ }126+127+private function checkUserId(Activity $activity, SearchFilter $filter): ?bool128+ {129+return $filter->getFilterValue() === $activity->user->getUuid() ? null : false;130+ }131+132+private function checkChannelId(Activity $activity, SearchFilter $filter): ?bool133+ {134+return $filter->getFilterValue() === $activity->getType() ? null : false;135+ }136+137+private function checkProviderId(Activity $activity, SearchFilter $filter): ?bool138+ {139+return $filter->getFilterValue() === $activity->getProvider() ? null : false;140+ }141+142+private function checkCategoryId(Activity $activity, SearchFilter $filter): ?bool143+ {144+$categoryId = $activity->getCategory()?->getUuid();145+if ($categoryId === null) {146+return null;147+ }148+149+return $filter->getFilterValue() === $categoryId ? null : false;150+ }151+152+private function checkMinDuration(Activity $activity, SearchFilter $filter): ?bool153+ {154+return $activity->getDuration() >= (float) $filter->getFilterValue() ? null : false;155+ }156+157+private function checkMaxDuration(Activity $activity, SearchFilter $filter): ?bool158+ {159+return $activity->getDuration() <= (float) $filter->getFilterValue() ? null : false;160+ }161+162+private function checkNotLogged(Activity $activity, SearchFilter $filter): ?bool163+ {164+if (! $filter->getFilterValue()) {165+return null;166+ }167+168+$isLogged = $activity->getCrmProviderId() !== null;169+$isInternal = $activity->isInternal();170+171+return (! $isLogged || $isInternal) ? null : false;172+ }173+174+private function checkOnlyRecorded(Activity $activity, SearchFilter $filter): ?bool175+ {176+$filterValue = (int) $filter->getFilterValue();177+$hasRecording = $activity->recording_state !== Activity::RECORDING_OFF;178+179+return match ($filterValue) {180+1 => $hasRecording ? null : false, // Only recorded181+2 => ! $hasRecording ? null : false, // Only non-recorded182+default => null,183+ };184+ }185+186+private function checkStageId(Activity $activity, SearchFilter $filter): ?bool187+ {188+$stageId = $activity->getStage()?->getUuid();189+if ($stageId === null) {190+return null; // No stage, let ES handle191+ }192+193+return $filter->getFilterValue() === $stageId ? null : false;194+ }195+196+private function checkStartDate(Activity $activity, SearchFilter $filter): ?bool197+ {198+$startTime = $activity->getActualStartTime();199+if ($startTime === null) {200+return null;201+ }202+203+$filterDate = Carbon::parse($filter->getFilterValue());204+205+return $startTime->gte($filterDate) ? null : false;206+ }207+208+private function checkEndDate(Activity $activity, SearchFilter $filter): ?bool209+ {210+$endTime = $activity->getActualEndTime();211+if ($endTime === null) {212+return null;213+ }214+215+$filterDate = Carbon::parse($filter->getFilterValue())->endOfDay();216+217+return $endTime->lte($filterDate) ? null : false;218+ }219+220+private function checkLanguages(Activity $activity, SearchFilter $filter): ?bool221+ {222+$activityLanguage = $activity->getLanguageCode();223+if ($activityLanguage === null) {224+return null;225+ }226+227+// Filter values are always base language codes (e.g., 'en', 'fr').228+// Extract base code from activity locale (e.g., en_GB -> en) to match ES query behavior.229+// See LanguageFilterDefinition::getQueries() which uses regex: $language . '_[a-z]{2}'230+$activityLangCode = explode('_', $activityLanguage)[0];231+$filterLanguage = $filter->getFilterValue();232+233+return $activityLangCode === $filterLanguage ? null : false;69 }234 }70}235}</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Expand
Listen
Gemini said
Gemini said
This code selection introduces a
pre-filtering mechanism
to the
Jiminny\Component\Nudge\Job
namespace. The primary goal is to optimize performance by validating an activity against search criteria in-memory before dispatching costly background jobs.
Core Functionality Changes
Core Functionality Changes
Selective Loading:
The
handle()
method now eager-loads
user.group
for activities and specifically filters for
FREQ_INSTANTLY
nudges and their associated search filters.
Pre-Dispatch Validation:
Instead of dispatching jobs for every instant nudge, the system now calls
activityMightMatchSearch()
.
Short-Circuiting:
If an activity fails a pre-filter check (e.g., mismatched user ID or duration), the job dispatch is skipped, and the event is logged with the specific mismatch reason.
Performance Metrics:
Adds summary logging at the end of the process to track:
Total searches processed.
Number of skipped dispatches.
The "Skip Rate" percentage.
Implemented Filter Checks
Implemented Filter Checks
The logic includes a
match
expression to validate various activity attributes against
SearchFilter
values:
Identity & Metadata:
Matches for
group_id
,
user_id
,
channel_id
, and
provider_id
.
Temporal & Duration:
* Validates
min_duration
and
max_duration
.
Checks
start_date
and
end_date
using Carbon parsing.
Activity State:
*
Logging:
Determines if an activity is logged to a CRM or is internal via
checkNotLogged
.
Recording:
Uses
checkOnlyRecorded
to filter based on whether a recording exists.
Categorization:
Checks for
category_id
,
stage_id
, and
languages
.
Note:
The language check specifically extracts base codes (e.g.,
en
from
en_GB
) to align with Elasticsearch behavior.
Logic Design
Logic Design
Nullable Returns:
Filter methods return
null
if a match is possible (or cannot be determined), and
false
only when a definitive mismatch is found.
Safe Fallback:
If a filter type is unknown (
default
), the system assumes a match and proceeds to dispatch, ensuring no false negatives.
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
You said what is the logic behind diff. Act as code reviewer. First review the changes then explain it and then evaluate. Try to find potential issues and bottlenecks
You said
what is the logic behind diff. Act as code reviewer. First review the changes then explain it and then evaluate. Try to find potential issues and bottlenecks
Expand
Listen
Show more options
Show thinking
Gemini said
Gemini said
Here is a review of the changes provided in the diff, broken down by your requested structure.
1. Review of Changes
1. Review of Changes
This PR refactors the
ProcessNudgeSearchJob
dispatching mechanism within the
handle()
method.
Query Optimization:
Eager loads necessary relationships (
user.group
,
filters
) and scopes the
nudges
relationship at the database level to only fetch
FREQ_INSTANTLY
records.
In-Memory Filtering:
Introduces a pre-filtering mechanism (
activityMightMatchSearch
) that checks the
Activity
against
SearchFilter
criteria before deciding to dispatch a job.
Helper Methods:
Adds 13 private
check*
methods to handle the specific comparison logic for different filter types (e.g., duration, dates, categories, stages).
Observability:
Adds structured logging to record exactly why a nudge was skipped and outputs a summary report (total, skipped, dispatched, skip rate) at the end of the execution.
2. Explanation of Logic
2. Explanation of Logic
The core philosophy of this change is
"veto-based short-circuiting"
.
Previously, the job fetched all searches with instant nudges for a team's users and blindly dispatched a queue job for every single one. The heavy lifting of deciding if the activity actually matched the search was likely deferred to the queue worker and Elasticsearch.
Now, the code evaluates the filters in the current process:
It iterates through each
Search
and its associated
SearchFilter
s.
It routes the filter to a specific
check*
method using a
match
expression based on the filter's property name.
The Veto:
The
check*
methods are designed to return
false
only if there is an absolute mismatch
(e.g., the filter requires a minimum duration of 10, but the activity is 5).
The Pass:
If the filter matches, or if the activity lacks the data needed to make a firm decision (e.g., no stage is assigned, or the filter type is unrecognized), the method returns
null
. This acts as a pass, delegating the final strict evaluation to Elasticsearch later in the pipeline.
If any filter returns
false
, the search is skipped, saving a queue dispatch.
3. Evaluation
3. Evaluation
Overall, this is a
highly effective performance optimization
.
Pros:
It significantly reduces queue bloat. By filtering out obvious mismatches in-memory, you save the overhead of serializing, dispatching, picking up, and processing jobs that are destined to fail or do nothing. The use of
match
makes the routing exceptionally clean, and the nullable return design is a smart way to avoid false negatives.
Cons/Trade-offs:
You are trading background queue worker time for a slight increase in synchronous memory and CPU usage on the current job. However, queue I/O is almost always more expensive than simple in-memory comparisons, making this a worthwhile trade.
4. Potential Issues & Bottlenecks
4. Potential Issues & Bottlenecks
While the logic is sound, there are a few architectural bottlenecks and risks introduced or maintained in this diff:
Potential N+1 Query / Lazy Loading Issues:
In the
handle
method, the activity is loaded with
Activity::with(['user.group'])
. However, inside your new
check*
methods, you are calling:
$activity->getCategory()?->getUuid()
$activity->getStage()?->getUuid()
If
category
and
stage
are Eloquent relationships and are not eager-loaded on the original
$activity
model, calling these methods inside a loop of
$totalSearches
will trigger lazy-loaded database queries.
Fix:
Update line 38 to:
$activity = Activity::with(['user.group', 'category', 'stage'])->...
Massive Memory Consumption (Pre-existing but critical):
Lines 39-41:
PHP
Download code
Copy code
$team
= Team::with([
'users'
])->findOrFail(
$activity
->user->team_id);
$usersIds
=
$team
->users->pluck(
'id'
)->toArray();
If a team has thousands of users,
Team::with(['users'])
hydrates thousands of full Eloquent User models into memory just to extract their IDs.
Fix:
Bypass hydrating the models entirely by querying the relationship directly:
$usersIds = $team->users()->pluck('id')->toArray();
Repeated Carbon Parsing in Loops:
In
checkStartDate
and
checkEndDate
, you parse the filter date:
Carbon::parse($filter->getFilterValue())
. If the same date filter applies to multiple searches, Carbon is being instantiated repeatedly in the loop. While Carbon is relatively fast, doing this hundreds of times adds unnecessary CPU cycles.
Fix:
This is a minor nitpick, but if performance is the absolute goal, you could memoize/cache the parsed filter values within the job.
Loose Type Comparisons:
In methods like
checkChannelId
or
checkLanguages
, you are using strict equality (
===
). Ensure that
$filter->getFilterValue()
(which is typically returned as a string from a database payload) matches the exact type returned by
$activity->getType()
or
$activityLangCode
. If one is an integer
1
and the other is a string
"1"
, the strict check will return
false
, incorrectly preventing the nudge from sending.
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said what would be your suggestion?
You said
what would be your suggestion?
Listen
Show more options
Show thinking
Gemini said
Gemini said
Here are actionable suggestions to address the potential issues and bottlenecks identified in the review. These optimizations focus on reducing memory footprint, preventing lazy-loading, and ensuring data type resilience.
1. Fix the N+1 Query Risk (Eager Loading)
1. Fix the N+1 Query Risk (Eager Loading)
Your
checkCategoryId
and
checkStageId
methods call
$activity->getCategory()
and
$activity->getStage()
. If these relationships aren't eager-loaded, Laravel will execute a new database query for every check inside the loop.
Suggestion:
Add
category
and
stage
to the initial eager-load array.
PHP
Download code
Copy code
// Before (Line 38)
$activity
= Activity::with([
'user.group'
])->uuid(
$this
->activityUuid,
false
)->firstOrFail();
// After
$activity
= Activity::with([
'user.group'
,
'category'
,
'stage'
])->uuid(
$this
->activityUuid,
false
)->firstOrFail();
2. Drastically Reduce Memory Usage
2. Drastically Reduce Memory Usage
Currently, you are hydrating full Eloquent
User
models into memory just to extract their IDs. If a team has hundreds or thousands of users, this will spike memory usage and potentially crash the worker.
Suggestion:
Use the relationship query builder to perform the
pluck
directly at the database level, bypassing Eloquent model hydration entirely.
PHP
Download code
Copy code
// Before (Lines 39-41)
$team
= Team::with([
'users'
])->findOrFail(
$activity
->user->team_id);
$usersIds
=
$team
->users->pluck(
'id'
)->toArray();
// After (No need to eager load 'users' on the Team model anymore)
$team
= Team::findOrFail(
$activity
->user->team_id);
$usersIds
=
$team
->users()->pluck(
'users.id'
)->toArray();
// Note the `()` after users
3. Harden Type Comparisons
3. Harden Type Comparisons
Since Elasticsearch and databases often return IDs or filter values as strings, strict comparison (
===
) against an Eloquent model's attribute (which might be cast to an integer) can cause false negatives.
Suggestion:
Cast your values before comparison, or use loose equality (
==
) if you are absolutely certain of the payload structure.
PHP
Download code
Copy code
// Example for checkChannelId (Lines 132-135)
private
function...
|
7897
|
NULL
|
NULL
|
NULL
|
|
8991
|
404
|
43
|
2026-05-08T11:53:55.745517+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778241235745_m2.jpg...
|
PhpStorm
|
Shelve Changes
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Diff
Changelist:
Changelist:
Changes
Show Diff
Rol Diff
Changelist:
Changelist:
Changes
Show Diff
Rollback...
Refresh
Group By
Expand All
Collapse All
11 files, folder partially checked
app 9 files, folder partially checked
Console/Commands 1 file, folder not checked
Exceptions 1 file, folder checked
RateLimitException.php, exception class checked
Jobs 3 files, folder checked
Activity/Import 1 file, folder checked
MatchCrmData.php, class checked
Crm 1 file, folder checked
MatchActivityCrmData.php, class checked
Middleware 1 file, folder checked
HandleHubspotRateLimit.php, class checked
Services/Crm/Hubspot 4 files, folder checked
Pagination 2 files, folder checked
HubspotPaginationService.php, class checked
PaginationState.php, class checked
Client.php, class checked
HubspotClientInterface.php, interface checked
config 1 file, folder not checked
.env.local not checked
app 9 files, folder partially checked
Console/Commands 1 file, folder not checked
Exceptions 1 file, folder checked
RateLimitException.php, exception class checked
Jobs 3 files, folder checked
Activity/Import 1 file, folder checked
MatchCrmData.php, class checked
Crm 1 file, folder checked
MatchActivityCrmData.php, class checked
Middleware 1 file, folder checked
HandleHubspotRateLimit.php, class checked
Services/Crm/Hubspot 4 files, folder checked
Pagination 2 files, folder checked
HubspotPaginationService.php, class checked
PaginationState.php, class checked
Client.php, class checked
HubspotClientInterface.php, interface checked
Console/Commands 1 file, folder not checked
Exceptions 1 file, folder checked
RateLimitException.php, exception class checked
RateLimitException.php, exception class checked
Jobs 3 files, folder checked
Activity/Import 1 file, folder checked
MatchCrmData.php, class checked
Crm 1 file, folder checked
MatchActivityCrmData.php, class checked
Middleware 1 file, folder checked
HandleHubspotRateLimit.php, class checked
Activity/Import 1 file, folder checked
MatchCrmData.php, class checked
MatchCrmData.php, class checked
Crm 1 file, folder checked
MatchActivityCrmData.php, class checked
MatchActivityCrmData.php, class checked
Middleware 1 file, folder checked
HandleHubspotRateLimit.php, class checked
HandleHubspotRateLimit.php, class checked
Services/Crm/Hubspot 4 files, folder checked
Pagination 2 files, folder checked
HubspotPaginationService.php, class checked
PaginationState.php, class checked
Client.php, class checked
HubspotClientInterface.php, interface checked
Pagination 2 files, folder checked
HubspotPaginationService.php, class checked
PaginationState.php, class checked
HubspotPaginationService.php, class checked
PaginationState.php, class checked
Client.php, class checked
HubspotClientInterface.php, interface checked
config 1 file, folder not checked
.env.local not checked
1 added 7 modified
A
Commit Message
Commit Message History
Previous Difference
Next Difference
Jump to Source
Compare Previous File
Compare Next File
Go to Changed File…
Side-by-side viewer
Do not ignore
Highlight words
Collapse Unchanged Fragments
Synchronize Scrolling
Disable Editing
Settings
Help
2 differences
12295204
<?php
declare(strict_types=1);
namespace Jiminny\Exceptions;
class RateLimitException extends LogicException
{
}
Current version
<?php
declare(strict_types=1);
namespace Jiminny\Exceptions;
use Throwable;
class RateLimitException extends LogicException
{
public function __construct(
string $message = '',
private readonly int $retryAfter = 1,
?Throwable $previous = null,
) {
parent::__construct($message, 0, $previous);
}
public function getRetryAfter(): int
{
return max($this->retryAfter, 1);
}
}
Help
Cancel
Shelve Changes...
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"Diff","depth":1,"bounds":{"left":0.25531915,"top":0.39185953,"width":0.013962766,"height":0.013567438},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Changelist:","depth":1,"bounds":{"left":0.51329786,"top":0.15802075,"width":0.022938829,"height":0.027134877},"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Changelist:","depth":1,"bounds":{"left":0.5375665,"top":0.15802075,"width":0.042220745,"height":0.027134877},"on_screen":true,"role_description":"pop up button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Changes","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Show Diff","depth":2,"bounds":{"left":0.25664893,"top":0.16201118,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Rollback...","depth":2,"bounds":{"left":0.26529256,"top":0.16201118,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Refresh","depth":2,"bounds":{"left":0.27393618,"top":0.16201118,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Group By","depth":2,"bounds":{"left":0.28490692,"top":0.16201118,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand All","depth":2,"bounds":{"left":0.49268618,"top":0.16201118,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":2,"bounds":{"left":0.5013298,"top":0.16201118,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"11 files, folder partially checked","depth":4,"bounds":{"left":0.26462767,"top":0.13328013,"width":0.03158245,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"app 9 files, folder partially checked","depth":5,"bounds":{"left":0.27094415,"top":0.15083799,"width":0.038231384,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Console/Commands 1 file, folder not checked","depth":6,"bounds":{"left":0.27726063,"top":0.16839585,"width":0.06881649,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Exceptions 1 file, folder checked","depth":6,"bounds":{"left":0.27726063,"top":0.1859537,"width":0.049867023,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"RateLimitException.php, exception class checked","depth":7,"bounds":{"left":0.2835771,"top":0.20351157,"width":0.064494684,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Jobs 3 files, folder checked","depth":6,"bounds":{"left":0.27726063,"top":0.22106944,"width":0.040226065,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Activity/Import 1 file, folder checked","depth":7,"bounds":{"left":0.2835771,"top":0.2386273,"width":0.057513297,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"MatchCrmData.php, class checked","depth":8,"bounds":{"left":0.28989363,"top":0.25618514,"width":0.055851065,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Crm 1 file, folder checked","depth":7,"bounds":{"left":0.2835771,"top":0.273743,"width":0.035904255,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"MatchActivityCrmData.php, class checked","depth":8,"bounds":{"left":0.28989363,"top":0.29130086,"width":0.071476065,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Middleware 1 file, folder checked","depth":7,"bounds":{"left":0.2835771,"top":0.30885875,"width":0.05119681,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"HandleHubspotRateLimit.php, class checked","depth":8,"bounds":{"left":0.28989363,"top":0.3264166,"width":0.076130316,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Services/Crm/Hubspot 4 files, folder checked","depth":6,"bounds":{"left":0.27726063,"top":0.34397447,"width":0.07712766,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Pagination 2 files, folder checked","depth":7,"bounds":{"left":0.2835771,"top":0.36153233,"width":0.051861703,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"HubspotPaginationService.php, class checked","depth":8,"bounds":{"left":0.28989363,"top":0.3790902,"width":0.07945479,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"PaginationState.php, class checked","depth":8,"bounds":{"left":0.28989363,"top":0.39664805,"width":0.057513297,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Client.php, class checked","depth":7,"bounds":{"left":0.2835771,"top":0.4142059,"width":0.036901597,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"HubspotClientInterface.php, interface checked","depth":7,"bounds":{"left":0.2835771,"top":0.43176377,"width":0.07280585,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"config 1 file, folder not checked","depth":5,"bounds":{"left":0.27094415,"top":0.44932163,"width":0.040226065,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":".env.local not checked","depth":5,"bounds":{"left":0.27094415,"top":0.4668795,"width":0.03557181,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"app 9 files, folder partially checked","depth":4,"bounds":{"left":0.27094415,"top":0.15083799,"width":0.038231384,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Console/Commands 1 file, folder not checked","depth":5,"bounds":{"left":0.27726063,"top":0.16839585,"width":0.06881649,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Exceptions 1 file, folder checked","depth":5,"bounds":{"left":0.27726063,"top":0.1859537,"width":0.049867023,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"RateLimitException.php, exception class checked","depth":6,"bounds":{"left":0.2835771,"top":0.20351157,"width":0.064494684,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Jobs 3 files, folder checked","depth":5,"bounds":{"left":0.27726063,"top":0.22106944,"width":0.040226065,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Activity/Import 1 file, folder checked","depth":6,"bounds":{"left":0.2835771,"top":0.2386273,"width":0.057513297,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"MatchCrmData.php, class checked","depth":7,"bounds":{"left":0.28989363,"top":0.25618514,"width":0.055851065,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Crm 1 file, folder checked","depth":6,"bounds":{"left":0.2835771,"top":0.273743,"width":0.035904255,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"MatchActivityCrmData.php, class checked","depth":7,"bounds":{"left":0.28989363,"top":0.29130086,"width":0.071476065,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Middleware 1 file, folder checked","depth":6,"bounds":{"left":0.2835771,"top":0.30885875,"width":0.05119681,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"HandleHubspotRateLimit.php, class checked","depth":7,"bounds":{"left":0.28989363,"top":0.3264166,"width":0.076130316,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Services/Crm/Hubspot 4 files, folder checked","depth":5,"bounds":{"left":0.27726063,"top":0.34397447,"width":0.07712766,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Pagination 2 files, folder checked","depth":6,"bounds":{"left":0.2835771,"top":0.36153233,"width":0.051861703,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"HubspotPaginationService.php, class checked","depth":7,"bounds":{"left":0.28989363,"top":0.3790902,"width":0.07945479,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"PaginationState.php, class checked","depth":7,"bounds":{"left":0.28989363,"top":0.39664805,"width":0.057513297,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Client.php, class checked","depth":6,"bounds":{"left":0.2835771,"top":0.4142059,"width":0.036901597,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"HubspotClientInterface.php, interface checked","depth":6,"bounds":{"left":0.2835771,"top":0.43176377,"width":0.07280585,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Console/Commands 1 file, folder not checked","depth":4,"bounds":{"left":0.27726063,"top":0.16839585,"width":0.06881649,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Exceptions 1 file, folder checked","depth":4,"bounds":{"left":0.27726063,"top":0.1859537,"width":0.049867023,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"RateLimitException.php, exception class checked","depth":5,"bounds":{"left":0.2835771,"top":0.20351157,"width":0.064494684,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"RateLimitException.php, exception class checked","depth":4,"bounds":{"left":0.2835771,"top":0.20351157,"width":0.064494684,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Jobs 3 files, folder checked","depth":4,"bounds":{"left":0.27726063,"top":0.22106944,"width":0.040226065,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Activity/Import 1 file, folder checked","depth":5,"bounds":{"left":0.2835771,"top":0.2386273,"width":0.057513297,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"MatchCrmData.php, class checked","depth":6,"bounds":{"left":0.28989363,"top":0.25618514,"width":0.055851065,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Crm 1 file, folder checked","depth":5,"bounds":{"left":0.2835771,"top":0.273743,"width":0.035904255,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"MatchActivityCrmData.php, class checked","depth":6,"bounds":{"left":0.28989363,"top":0.29130086,"width":0.071476065,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Middleware 1 file, folder checked","depth":5,"bounds":{"left":0.2835771,"top":0.30885875,"width":0.05119681,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"HandleHubspotRateLimit.php, class checked","depth":6,"bounds":{"left":0.28989363,"top":0.3264166,"width":0.076130316,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Activity/Import 1 file, folder checked","depth":4,"bounds":{"left":0.2835771,"top":0.2386273,"width":0.057513297,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"MatchCrmData.php, class checked","depth":5,"bounds":{"left":0.28989363,"top":0.25618514,"width":0.055851065,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"MatchCrmData.php, class checked","depth":4,"bounds":{"left":0.28989363,"top":0.25618514,"width":0.055851065,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Crm 1 file, folder checked","depth":4,"bounds":{"left":0.2835771,"top":0.273743,"width":0.035904255,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"MatchActivityCrmData.php, class checked","depth":5,"bounds":{"left":0.28989363,"top":0.29130086,"width":0.071476065,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"MatchActivityCrmData.php, class checked","depth":4,"bounds":{"left":0.28989363,"top":0.29130086,"width":0.071476065,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Middleware 1 file, folder checked","depth":4,"bounds":{"left":0.2835771,"top":0.30885875,"width":0.05119681,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"HandleHubspotRateLimit.php, class checked","depth":5,"bounds":{"left":0.28989363,"top":0.3264166,"width":0.076130316,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"HandleHubspotRateLimit.php, class checked","depth":4,"bounds":{"left":0.28989363,"top":0.3264166,"width":0.076130316,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Services/Crm/Hubspot 4 files, folder checked","depth":4,"bounds":{"left":0.27726063,"top":0.34397447,"width":0.07712766,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Pagination 2 files, folder checked","depth":5,"bounds":{"left":0.2835771,"top":0.36153233,"width":0.051861703,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"HubspotPaginationService.php, class checked","depth":6,"bounds":{"left":0.28989363,"top":0.3790902,"width":0.07945479,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"PaginationState.php, class checked","depth":6,"bounds":{"left":0.28989363,"top":0.39664805,"width":0.057513297,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Client.php, class checked","depth":5,"bounds":{"left":0.2835771,"top":0.4142059,"width":0.036901597,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"HubspotClientInterface.php, interface checked","depth":5,"bounds":{"left":0.2835771,"top":0.43176377,"width":0.07280585,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Pagination 2 files, folder checked","depth":4,"bounds":{"left":0.2835771,"top":0.36153233,"width":0.051861703,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"HubspotPaginationService.php, class checked","depth":5,"bounds":{"left":0.28989363,"top":0.3790902,"width":0.07945479,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"PaginationState.php, class checked","depth":5,"bounds":{"left":0.28989363,"top":0.39664805,"width":0.057513297,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"HubspotPaginationService.php, class checked","depth":4,"bounds":{"left":0.28989363,"top":0.3790902,"width":0.07945479,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"PaginationState.php, class checked","depth":4,"bounds":{"left":0.28989363,"top":0.39664805,"width":0.057513297,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Client.php, class checked","depth":4,"bounds":{"left":0.2835771,"top":0.4142059,"width":0.036901597,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"HubspotClientInterface.php, interface checked","depth":4,"bounds":{"left":0.2835771,"top":0.43176377,"width":0.07280585,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"config 1 file, folder not checked","depth":4,"bounds":{"left":0.27094415,"top":0.44932163,"width":0.040226065,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":".env.local not checked","depth":4,"bounds":{"left":0.27094415,"top":0.4668795,"width":0.03557181,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1 added 7 modified","depth":1,"bounds":{"left":0.25531915,"top":0.254589,"width":0.32446808,"height":0.016759777},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"A","depth":2,"bounds":{"left":0.2556516,"top":0.3008779,"width":0.3238032,"height":0.087789305},"on_screen":true,"value":"A","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Commit Message","depth":1,"bounds":{"left":0.25531915,"top":0.28252193,"width":0.03557181,"height":0.013567438},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Commit Message History","depth":2,"bounds":{"left":0.5711436,"top":0.27853152,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Previous Difference","depth":2,"bounds":{"left":0.25664893,"top":0.41340783,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Difference","depth":2,"bounds":{"left":0.26529256,"top":0.41340783,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Jump to Source","depth":2,"bounds":{"left":0.27393618,"top":0.41340783,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Compare Previous File","depth":2,"bounds":{"left":0.28490692,"top":0.41340783,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Compare Next File","depth":2,"bounds":{"left":0.29355052,"top":0.41340783,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Go to Changed File…","depth":2,"bounds":{"left":0.30219415,"top":0.41340783,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Side-by-side viewer","depth":2,"bounds":{"left":0.3118351,"top":0.41340783,"width":0.04720745,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Do not ignore","depth":2,"bounds":{"left":0.36336437,"top":0.41340783,"width":0.03557181,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Highlight words","depth":2,"bounds":{"left":0.40093085,"top":0.41340783,"width":0.03956117,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse Unchanged Fragments","depth":2,"bounds":{"left":0.44148937,"top":0.41340783,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Synchronize Scrolling","depth":2,"bounds":{"left":0.45013297,"top":0.41340783,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Disable Editing","depth":2,"bounds":{"left":0.4587766,"top":0.41340783,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Settings","depth":2,"bounds":{"left":0.46742022,"top":0.41340783,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Help","depth":2,"bounds":{"left":0.47839096,"top":0.41340783,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2 differences","depth":1,"bounds":{"left":0.5515292,"top":0.41181165,"width":0.026928192,"height":0.022346368},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"12295204","depth":1,"bounds":{"left":0.26196808,"top":0.43415803,"width":0.023603724,"height":0.013567438},"on_screen":true,"value":"12295204","help_text":"text/plain","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Exceptions;\n\nclass RateLimitException extends LogicException\n{\n}","depth":2,"bounds":{"left":0.25531915,"top":0.42697525,"width":0.1456117,"height":0.24581006},"on_screen":true,"lines":[{"char_start":0,"char_count":6,"bounds":{"left":0.2613032,"top":0.1452514,"width":0.0026595744,"height":0.014365523}},{"char_start":7,"char_count":25,"bounds":{"left":0.2613032,"top":0.16280925,"width":0.06216755,"height":0.014365523}},{"char_start":33,"char_count":30,"bounds":{"left":0.2613032,"top":0.19792499,"width":0.07513298,"height":0.014365523}},{"char_start":64,"char_count":48,"bounds":{"left":0.2613032,"top":0.2330407,"width":0.12167553,"height":0.014365523}},{"char_start":112,"char_count":2,"bounds":{"left":0.2613032,"top":0.25059855,"width":0.0026595744,"height":0.014365523}},{"char_start":114,"char_count":1,"bounds":{"left":0.2613032,"top":0.26815644,"width":0.0026595744,"height":0.014365523}}],"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Exceptions;\n\nclass RateLimitException extends LogicException\n{\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"Current version","depth":1,"bounds":{"left":0.44049203,"top":0.43415803,"width":0.13796543,"height":0.013567438},"on_screen":true,"value":"Current version","help_text":"text/plain","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Exceptions;\n\nuse Throwable;\n\nclass RateLimitException extends LogicException\n{\n public function __construct(\n string $message = '',\n private readonly int $retryAfter = 1,\n ?Throwable $previous = null,\n ) {\n parent::__construct($message, 0, $previous);\n }\n\n public function getRetryAfter(): int\n {\n return max($this->retryAfter, 1);\n }\n}","depth":2,"bounds":{"left":0.44514626,"top":0.42697525,"width":0.14228724,"height":0.49162012},"on_screen":true,"lines":[{"char_start":0,"char_count":6,"bounds":{"left":0.44514626,"top":0.1452514,"width":0.0026595744,"height":0.014365523}},{"char_start":7,"char_count":25,"bounds":{"left":0.44514626,"top":0.16280925,"width":0.06216755,"height":0.014365523}},{"char_start":33,"char_count":30,"bounds":{"left":0.44514626,"top":0.19792499,"width":0.07513298,"height":0.014365523}},{"char_start":64,"char_count":15,"bounds":{"left":0.44514626,"top":0.2330407,"width":0.036236703,"height":0.014365523}},{"char_start":80,"char_count":48,"bounds":{"left":0.44514626,"top":0.26815644,"width":0.12167553,"height":0.014365523}},{"char_start":128,"char_count":2,"bounds":{"left":0.44514626,"top":0.2857143,"width":0.0026595744,"height":0.014365523}},{"char_start":130,"char_count":33,"bounds":{"left":0.44514626,"top":0.30327216,"width":0.08277926,"height":0.014365523}},{"char_start":163,"char_count":30,"bounds":{"left":0.44514626,"top":0.32083002,"width":0.07513298,"height":0.014365523}},{"char_start":193,"char_count":46,"bounds":{"left":0.44514626,"top":0.33838788,"width":0.11635638,"height":0.014365523}},{"char_start":239,"char_count":37,"bounds":{"left":0.44514626,"top":0.35594574,"width":0.0930851,"height":0.014365523}},{"char_start":276,"char_count":8,"bounds":{"left":0.44514626,"top":0.3735036,"width":0.017952127,"height":0.014365523}},{"char_start":284,"char_count":53,"bounds":{"left":0.44514626,"top":0.39106146,"width":0.13464096,"height":0.014365523}},{"char_start":337,"char_count":6,"bounds":{"left":0.44514626,"top":0.4086193,"width":0.012965426,"height":0.014365523}},{"char_start":344,"char_count":41,"bounds":{"left":0.44514626,"top":0.44373503,"width":0.10372341,"height":0.014365523}},{"char_start":385,"char_count":6,"bounds":{"left":0.44514626,"top":0.4612929,"width":0.012965426,"height":0.014365523}}],"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Exceptions;\n\nuse Throwable;\n\nclass RateLimitException extends LogicException\n{\n public function __construct(\n string $message = '',\n private readonly int $retryAfter = 1,\n ?Throwable $previous = null,\n ) {\n parent::__construct($message, 0, $previous);\n }\n\n public function getRetryAfter(): int\n {\n return max($this->retryAfter, 1);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Help","depth":1,"bounds":{"left":0.25531915,"top":0.65363127,"width":0.00930851,"height":0.027134877},"on_screen":true,"help_text":"Show help contents","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Cancel","depth":1,"bounds":{"left":0.50764626,"top":0.65363127,"width":0.025930852,"height":0.027134877},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Shelve Changes","depth":1,"bounds":{"left":0.5355718,"top":0.65363127,"width":0.044215426,"height":0.027134877},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-5322889190144704592
|
-327988352975895108
|
visual_change
|
accessibility
|
NULL
|
Diff
Changelist:
Changelist:
Changes
Show Diff
Rol Diff
Changelist:
Changelist:
Changes
Show Diff
Rollback...
Refresh
Group By
Expand All
Collapse All
11 files, folder partially checked
app 9 files, folder partially checked
Console/Commands 1 file, folder not checked
Exceptions 1 file, folder checked
RateLimitException.php, exception class checked
Jobs 3 files, folder checked
Activity/Import 1 file, folder checked
MatchCrmData.php, class checked
Crm 1 file, folder checked
MatchActivityCrmData.php, class checked
Middleware 1 file, folder checked
HandleHubspotRateLimit.php, class checked
Services/Crm/Hubspot 4 files, folder checked
Pagination 2 files, folder checked
HubspotPaginationService.php, class checked
PaginationState.php, class checked
Client.php, class checked
HubspotClientInterface.php, interface checked
config 1 file, folder not checked
.env.local not checked
app 9 files, folder partially checked
Console/Commands 1 file, folder not checked
Exceptions 1 file, folder checked
RateLimitException.php, exception class checked
Jobs 3 files, folder checked
Activity/Import 1 file, folder checked
MatchCrmData.php, class checked
Crm 1 file, folder checked
MatchActivityCrmData.php, class checked
Middleware 1 file, folder checked
HandleHubspotRateLimit.php, class checked
Services/Crm/Hubspot 4 files, folder checked
Pagination 2 files, folder checked
HubspotPaginationService.php, class checked
PaginationState.php, class checked
Client.php, class checked
HubspotClientInterface.php, interface checked
Console/Commands 1 file, folder not checked
Exceptions 1 file, folder checked
RateLimitException.php, exception class checked
RateLimitException.php, exception class checked
Jobs 3 files, folder checked
Activity/Import 1 file, folder checked
MatchCrmData.php, class checked
Crm 1 file, folder checked
MatchActivityCrmData.php, class checked
Middleware 1 file, folder checked
HandleHubspotRateLimit.php, class checked
Activity/Import 1 file, folder checked
MatchCrmData.php, class checked
MatchCrmData.php, class checked
Crm 1 file, folder checked
MatchActivityCrmData.php, class checked
MatchActivityCrmData.php, class checked
Middleware 1 file, folder checked
HandleHubspotRateLimit.php, class checked
HandleHubspotRateLimit.php, class checked
Services/Crm/Hubspot 4 files, folder checked
Pagination 2 files, folder checked
HubspotPaginationService.php, class checked
PaginationState.php, class checked
Client.php, class checked
HubspotClientInterface.php, interface checked
Pagination 2 files, folder checked
HubspotPaginationService.php, class checked
PaginationState.php, class checked
HubspotPaginationService.php, class checked
PaginationState.php, class checked
Client.php, class checked
HubspotClientInterface.php, interface checked
config 1 file, folder not checked
.env.local not checked
1 added 7 modified
A
Commit Message
Commit Message History
Previous Difference
Next Difference
Jump to Source
Compare Previous File
Compare Next File
Go to Changed File…
Side-by-side viewer
Do not ignore
Highlight words
Collapse Unchanged Fragments
Synchronize Scrolling
Disable Editing
Settings
Help
2 differences
12295204
<?php
declare(strict_types=1);
namespace Jiminny\Exceptions;
class RateLimitException extends LogicException
{
}
Current version
<?php
declare(strict_types=1);
namespace Jiminny\Exceptions;
use Throwable;
class RateLimitException extends LogicException
{
public function __construct(
string $message = '',
private readonly int $retryAfter = 1,
?Throwable $previous = null,
) {
parent::__construct($message, 0, $previous);
}
public function getRetryAfter(): int
{
return max($this->retryAfter, 1);
}
}
Help
Cancel
Shelve Changes...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
9076
|
406
|
43
|
2026-05-08T12:00:10.913595+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778241610913_m2.jpg...
|
Firefox
|
Оптичен интернет за дома - EON телевизия | Vivacom Оптичен интернет за дома - EON телевизия | Vivacom | 5G — Personal...
|
True
|
www.vivacom.bg/internet/optichen-internet
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Pull requests · screenpipe/screenpipe · GitHub
Pul Pull requests · screenpipe/screenpipe · GitHub
Pull requests · screenpipe/screenpipe · GitHub
Home | Hostinger
Home | Hostinger
Login – Nginx Proxy Manager
Login – Nginx Proxy Manager
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Премини към основното съдържание
Активиране на достъпност за хора със слабо зрение
Отворете менюто за достъпност
ЧАСТНИ КЛИЕНТИ
ЧАСТНИ КЛИЕНТИ
БИЗНЕС КЛИЕНТИ
БИЗНЕС КЛИЕНТИ
МАГАЗИНИ
МАГАЗИНИ
ГЛЕДАЙ EON
ГЛЕДАЙ EON
КОНТАКТИ
КОНТАКТИ
ОБЩИ УСЛОВИЯ
ОБЩИ УСЛОВИЯ
КАРТИ НА ПОКРИТИЕТО
КАРТИ НА ПОКРИТИЕТО
Vivacom Logo
Мобилни услуги
Мобилни услуги
Устройства
Устройства
EON
EON
Интернет
Интернет
Други услуги
Други услуги
Помощ
Помощ
Cart
Оптичен интернет
Оптичен интернет
Вземи Fiber с
50% отстъпка
за първите 2 месеца
и получаваш безплатен Wi-Fi 6 рутер.
Оптичен интернет Интернет за отдалечени места
Оптичен интернет
Интернет за
отдалечени места
ОПТИЧЕН ИНТЕРНЕТ
ОПТИЧЕН ИНТЕРНЕТ
FiberNet L
FiberNet L
до 200 Mbps за download до 100 Mbps за upload
до 200 Mbps
за download
до 100 Mbps за upload
Безплатен Wi-Fi рутер
Безплатен Wi-Fi рутер
Повече детайли
Повече детайли
6.60€
|
12.91лв.
/мес.
след 2 месеца 13.19€ | 25.80лв.
/мес.
Провери покритие Провери покритие
Провери покритие
Провери покритие
Най-продаван
FiberNet XL
FiberNet XL
до 600 Mbps за download до 400 Mbps за upload
до 600 Mbps
за download
до 400 Mbps за upload
Безплатен Wi-Fi рутер
Безплатен Wi-Fi рутер
Повече детайли
Повече детайли
8.95€
|
17.50лв.
/мес.
след 2 месеца 17.90€ | 35.01лв.
/мес.
Провери покритие Провери покритие
Провери покритие
Провери покритие
FiberNet XΧL
FiberNet XΧL
до 2, 000 Mbps за download до 1, 000 Mbps за upload
до 2, 000 Mbps
за download
до 1, 000 Mbps за upload
Безплатен Wi-Fi рутер
Безплатен Wi-Fi рутер
Повече детайли
Повече детайли
13.94€
|
27.26лв.
/мес.
след 2 месеца 27.90€ | 54.57лв.
/мес.
Провери покритие Провери покритие
Провери покритие
Провери покритие
FiberNet 10G
FiberNet 10G
10, 000 Mbps max download speed 2, 000 Mbps max upload speed
10, 000 Mbps
max download speed
2, 000 Mbps max upload speed
Повече детайли
Повече детайли
38.45€
|
75.20лв.
/мес.
след 2 месеца 76.90€ | 150.40лв.
/мес.
Провери покритие Провери покритие
Провери покритие
Провери покритие
ПОЛЗИ
ПОЛЗИ
Супер бърза интернет скорост
Безплатен Wi-Fi рутер
24/7 техническа поддръжка
Допълнителни услуги
Антивирусна програма
0 € | 0 лв.
/мес.
Статичен IP адрес
1.02 € | 1.99 лв.
/мес.
Close
Богомил Райнов 4, 1000 София
Въведете друг адрес
Въведете друг адрес
НАЛИЧНИ ИНТЕРНЕТ ПЛАНОВЕ
НАЛИЧНИ ИНТЕРНЕТ ПЛАНОВЕ
FiberNet L
FiberNet L
до 200 Mbps за download до 100 Mbps за upload
до 200 Mbps
за download
до 100 Mbps за upload
Безплатен Wi-Fi рутер
Безплатен Wi-Fi рутер
5.95€
|
11.64лв.
/мес.
след 2 месеца 11.90€ | 23.27лв.
/мес.
Поръчай Поръчай
Поръчай
Поръчай
Избран план
FiberNet XL
FiberNet XL
до 600 Mbps за download до 400 Mbps за upload
до 600 Mbps
за download
до 400 Mbps за upload
Безплатен Wi-Fi рутер
Безплатен Wi-Fi рутер
8.95€
|
17.50лв.
/мес.
след 2 месеца 17.90€ | 35.01лв.
/мес.
Поръчай Поръчай
Поръчай
Поръчай
FiberNet 1000
FiberNet 1000
до 1000 Mbps за download до 700 Mbps за upload
до 1000 Mbps
за download
до 700 Mbps за upload
Безплатен Wi-Fi рутер
Безплатен Wi-Fi рутер
10.69€
|
20.91лв.
/мес.
след 2 месеца 21.37€ | 41.80лв.
/мес.
Поръчай Поръчай
Поръчай
Поръчай
Компанията
Компанията
За нас
За нас
Етика и съответствие
Етика и съответствие
Марката Vivacom
Марката Vivacom
Мениджмънт
Мениджмънт
Социална отговорност
Социална отговорност
Новини
Новини
Кариери
Кариери
Доставчици
Доставчици
Доклад за устойчиво развитие
Доклад за устойчиво развитие
Частни клиенти
Частни клиенти
Мобилни планове
Мобилни планове
Мобилен интернет
Мобилен интернет
Устройства
Устройства
Интернет пакети
Интернет пакети
Програма Лоялен клиент
Програма Лоялен клиент
Правила и условия
Правила и условия
Общи условия
Общи условия
Мобилно покритие
Мобилно покритие
Лични данни
Лични данни
Правила за ползване
Правила за ползване
Роуминг
Роуминг
Политика за бисквитките
Политика за бисквитките
Полезни връзки
Полезни връзки
Устройство в сервиз
Устройство в сервиз
Спешни номера
Спешни номера
Активиране на EON TV
Активиране на EON TV
Настройки на CA модул
Настройки на CA модул
Застраховки
Застраховки
Планове за хора с увреждания
Планове за хора с увреждания
Достъпност на сайта
Достъпност на сайта
Електронни фактури
Електронни фактури
EUR BGN
Валутен курс: 1 EUR = 1.95583 лв.
© VIVACOM 2026
google app - целевият уебсайт може да не е наличен
App store - отвори в нов раздел
Huawei store - отвори в нов раздел
Facebook
TikTok
YouTube
Instagram
Linkedin
United group - отвори в нов раздел
Отворена джаджа за чат
1
Open CMP widget...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Pull requests · screenpipe/screenpipe · GitHub","depth":4,"bounds":{"left":0.26097074,"top":0.0518755,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests · screenpipe/screenpipe · GitHub","depth":5,"bounds":{"left":0.27426863,"top":0.06304868,"width":0.080784574,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Home | Hostinger","depth":4,"bounds":{"left":0.26097074,"top":0.08459697,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Home | Hostinger","depth":5,"bounds":{"left":0.27426863,"top":0.09577015,"width":0.03025266,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Login – Nginx Proxy Manager","depth":4,"bounds":{"left":0.26097074,"top":0.11731844,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Login – Nginx Proxy Manager","depth":5,"bounds":{"left":0.27426863,"top":0.12849163,"width":0.05069814,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Screenpipe — Archive","depth":4,"bounds":{"left":0.26097074,"top":0.15003991,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Screenpipe — Archive","depth":5,"bounds":{"left":0.27426863,"top":0.16121309,"width":0.037898935,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: archive.db","depth":4,"bounds":{"left":0.26097074,"top":0.18276137,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: archive.db","depth":5,"bounds":{"left":0.27426863,"top":0.19393456,"width":0.040724736,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: db.sqlite","depth":4,"bounds":{"left":0.26097074,"top":0.21548285,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: db.sqlite","depth":5,"bounds":{"left":0.27426863,"top":0.22665602,"width":0.03756649,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub","depth":4,"bounds":{"left":0.26097074,"top":0.2482043,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub","depth":5,"bounds":{"left":0.27426863,"top":0.25937748,"width":0.11469415,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"DXP4800PLUS-B5F8","depth":4,"bounds":{"left":0.26097074,"top":0.28092578,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"DXP4800PLUS-B5F8","depth":5,"bounds":{"left":0.27426863,"top":0.29209897,"width":0.036901597,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Оптичен интернет за дома - EON телевизия | Vivacom | 5G","depth":4,"bounds":{"left":0.26097074,"top":0.31364724,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Оптичен интернет за дома - EON телевизия | Vivacom | 5G","depth":5,"bounds":{"left":0.27426863,"top":0.32482043,"width":0.105884306,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.36236703,"top":0.32083002,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.26379654,"top":0.34796488,"width":0.108211435,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.26379654,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"bounds":{"left":0.27476728,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.28590426,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.29704124,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bitwarden","depth":6,"bounds":{"left":0.3081782,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Премини към основното съдържание","depth":7,"bounds":{"left":0.38730052,"top":0.0,"width":0.10472074,"height":0.05027933},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Активиране на достъпност за хора със слабо зрение","depth":7,"bounds":{"left":0.38730052,"top":0.0,"width":0.10472074,"height":0.05027933},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Отворете менюто за достъпност","depth":7,"bounds":{"left":0.38730052,"top":0.0,"width":0.10472074,"height":0.05027933},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"ЧАСТНИ КЛИЕНТИ","depth":10,"bounds":{"left":0.41539228,"top":0.0,"width":0.0631649,"height":0.037110932},"on_screen":false,"help_text":"Частни клиенти","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ЧАСТНИ КЛИЕНТИ","depth":11,"bounds":{"left":0.42337102,"top":0.0,"width":0.04720745,"height":0.017557861},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"БИЗНЕС КЛИЕНТИ","depth":10,"bounds":{"left":0.47855717,"top":0.0,"width":0.062832445,"height":0.037110932},"on_screen":false,"help_text":"Бизнес клиенти","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"БИЗНЕС КЛИЕНТИ","depth":11,"bounds":{"left":0.4865359,"top":0.0,"width":0.046875,"height":0.017557861},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"МАГАЗИНИ","depth":10,"bounds":{"left":0.67985374,"top":0.0,"width":0.04488032,"height":0.037110932},"on_screen":false,"help_text":"Магазини","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"МАГАЗИНИ","depth":11,"bounds":{"left":0.6878325,"top":0.0,"width":0.028922873,"height":0.017557861},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"ГЛЕДАЙ EON","depth":10,"bounds":{"left":0.72473407,"top":0.0,"width":0.04837101,"height":0.037110932},"on_screen":false,"help_text":"Гледай EON","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ГЛЕДАЙ EON","depth":11,"bounds":{"left":0.73271275,"top":0.0,"width":0.032413565,"height":0.017557861},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"КОНТАКТИ","depth":10,"bounds":{"left":0.773105,"top":0.0,"width":0.044049203,"height":0.037110932},"on_screen":false,"help_text":"Контакти","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"КОНТАКТИ","depth":11,"bounds":{"left":0.78108376,"top":0.0,"width":0.028091755,"height":0.017557861},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"ОБЩИ УСЛОВИЯ","depth":10,"bounds":{"left":0.8171542,"top":0.0,"width":0.058011968,"height":0.037110932},"on_screen":false,"help_text":"Общи условия","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ОБЩИ УСЛОВИЯ","depth":11,"bounds":{"left":0.82513297,"top":0.0,"width":0.042054523,"height":0.017557861},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"КАРТИ НА ПОКРИТИЕТО","depth":10,"bounds":{"left":0.87516624,"top":0.0,"width":0.07829122,"height":0.037110932},"on_screen":false,"help_text":"Карти на покритието","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"КАРТИ НА ПОКРИТИЕТО","depth":11,"bounds":{"left":0.883145,"top":0.0,"width":0.062333778,"height":0.017557861},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Vivacom Logo","depth":8,"bounds":{"left":0.41539228,"top":0.0,"width":0.08643617,"height":0.0207502},"on_screen":false,"help_text":"Home","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Мобилни услуги","depth":10,"bounds":{"left":0.67869014,"top":0.0,"width":0.053523935,"height":0.021548284},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Мобилни услуги","depth":11,"bounds":{"left":0.67869014,"top":0.0,"width":0.053523935,"height":0.021947326},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Устройства","depth":10,"bounds":{"left":0.74551195,"top":0.0,"width":0.043218084,"height":0.021548284},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Устройства","depth":11,"bounds":{"left":0.74551195,"top":0.0,"width":0.043218084,"height":0.021947326},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"EON","depth":10,"bounds":{"left":0.80202794,"top":0.0,"width":0.013464096,"height":0.021548284},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"EON","depth":11,"bounds":{"left":0.80202794,"top":0.0,"width":0.013464096,"height":0.021947326},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Интернет","depth":10,"bounds":{"left":0.8287899,"top":0.0,"width":0.03673537,"height":0.021548284},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Интернет","depth":11,"bounds":{"left":0.8287899,"top":0.0,"width":0.03673537,"height":0.021947326},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Други услуги","depth":10,"bounds":{"left":0.87882316,"top":0.0,"width":0.044215426,"height":0.021548284},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Други услуги","depth":11,"bounds":{"left":0.87882316,"top":0.0,"width":0.044215426,"height":0.021947326},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Помощ","depth":10,"bounds":{"left":0.93633646,"top":0.0,"width":0.023769947,"height":0.021548284},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Помощ","depth":11,"bounds":{"left":0.93633646,"top":0.0,"width":0.023769947,"height":0.021947326},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Cart","depth":8,"bounds":{"left":0.9734042,"top":0.0,"width":0.026595745,"height":0.08619314},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Оптичен интернет","depth":9,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Оптичен интернет","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Вземи Fiber с","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"50% отстъпка","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"за първите 2 месеца","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"и получаваш безплатен Wi-Fi 6 рутер.","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Оптичен интернет Интернет за отдалечени места","depth":8,"on_screen":false,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Оптичен интернет","depth":10,"bounds":{"left":0.6180186,"top":0.006384677,"width":0.05518617,"height":0.017956903},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Интернет за","depth":10,"bounds":{"left":0.71043885,"top":0.0,"width":0.03723404,"height":0.017956903},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"отдалечени места","depth":10,"bounds":{"left":0.7027925,"top":0.014365523,"width":0.052526597,"height":0.017956903},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"ОПТИЧЕН ИНТЕРНЕТ","depth":9,"bounds":{"left":0.65009975,"top":0.07581804,"width":0.07446808,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ОПТИЧЕН ИНТЕРНЕТ","depth":10,"bounds":{"left":0.6540891,"top":0.075019956,"width":0.06648936,"height":0.021947326},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"FiberNet L","depth":12,"bounds":{"left":0.50199467,"top":0.14844373,"width":0.076296546,"height":0.037110932},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"FiberNet L","depth":13,"bounds":{"left":0.50199467,"top":0.14764565,"width":0.04305186,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"до 200 Mbps за download до 100 Mbps за upload","depth":12,"bounds":{"left":0.51263297,"top":0.20151636,"width":0.06565824,"height":0.054269753},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"до 200 Mbps","depth":13,"bounds":{"left":0.51263297,"top":0.20111732,"width":0.04089096,"height":0.021947326},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"за download","depth":13,"bounds":{"left":0.51263297,"top":0.22186752,"width":0.031083776,"height":0.017956903},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"до 100 Mbps за upload","depth":13,"bounds":{"left":0.51263297,"top":0.23822825,"width":0.055518616,"height":0.017956903},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Безплатен Wi-Fi рутер","depth":12,"bounds":{"left":0.51263297,"top":0.26536313,"width":0.06565824,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Безплатен Wi-Fi рутер","depth":13,"bounds":{"left":0.51263297,"top":0.26456505,"width":0.05435505,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Повече детайли","depth":12,"bounds":{"left":0.50199467,"top":0.29768556,"width":0.049867023,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Повече детайли","depth":13,"bounds":{"left":0.51329786,"top":0.29688746,"width":0.03856383,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"6.60€","depth":14,"bounds":{"left":0.50199467,"top":0.3347965,"width":0.02543218,"height":0.030726258},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"|","depth":14,"bounds":{"left":0.5284242,"top":0.3347965,"width":0.0023271276,"height":0.030726258},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"12.91лв.","depth":14,"bounds":{"left":0.5319149,"top":0.3347965,"width":0.033909574,"height":0.030726258},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/мес.","depth":14,"bounds":{"left":0.56582445,"top":0.34836394,"width":0.00880984,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"след 2 месеца 13.19€ | 25.80лв.","depth":13,"bounds":{"left":0.50199467,"top":0.36472467,"width":0.06648936,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/мес.","depth":13,"bounds":{"left":0.56848407,"top":0.36632082,"width":0.009807181,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Провери покритие Провери покритие","depth":11,"bounds":{"left":0.50199467,"top":0.40223464,"width":0.076296546,"height":0.04030327},"on_screen":true,"help_text":"Провери покритие","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Провери покритие","depth":13,"bounds":{"left":0.5142952,"top":0.41340783,"width":0.051861703,"height":0.017956903},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Провери покритие","depth":13,"bounds":{"left":0.5142952,"top":0.4293695,"width":0.051861703,"height":0.017956903},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Най-продаван","depth":12,"bounds":{"left":0.62017953,"top":0.11612131,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"FiberNet XL","depth":12,"bounds":{"left":0.5962433,"top":0.14844373,"width":0.07662899,"height":0.037110932},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"FiberNet XL","depth":13,"bounds":{"left":0.5962433,"top":0.14764565,"width":0.049035903,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"до 600 Mbps за download до 400 Mbps за upload","depth":12,"bounds":{"left":0.6068817,"top":0.20151636,"width":0.065990694,"height":0.054269753},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"до 600 Mbps","depth":13,"bounds":{"left":0.6068817,"top":0.20111732,"width":0.041223403,"height":0.021947326},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"за download","depth":13,"bounds":{"left":0.6068817,"top":0.22186752,"width":0.03125,"height":0.017956903},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"до 400 Mbps за upload","depth":13,"bounds":{"left":0.6068817,"top":0.23822825,"width":0.056848403,"height":0.017956903},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Безплатен Wi-Fi рутер","depth":12,"bounds":{"left":0.6068817,"top":0.26536313,"width":0.065990694,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Безплатен Wi-Fi рутер","depth":13,"bounds":{"left":0.6068817,"top":0.26456505,"width":0.05435505,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Повече детайли","depth":12,"bounds":{"left":0.5962433,"top":0.29768556,"width":0.049867023,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Повече детайли","depth":13,"bounds":{"left":0.60754657,"top":0.29688746,"width":0.03856383,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"8.95€","depth":14,"bounds":{"left":0.5962433,"top":0.3347965,"width":0.024767287,"height":0.030726258},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"|","depth":14,"bounds":{"left":0.62200797,"top":0.3347965,"width":0.0023271276,"height":0.030726258},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"17.50лв.","depth":14,"bounds":{"left":0.62549865,"top":0.3347965,"width":0.03507314,"height":0.030726258},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/мес.","depth":14,"bounds":{"left":0.6605718,"top":0.34836394,"width":0.00880984,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"след 2 месеца 17.90€ | 35.01лв.","depth":13,"bounds":{"left":0.5962433,"top":0.36472467,"width":0.06665558,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/мес.","depth":13,"bounds":{"left":0.66289896,"top":0.36632082,"width":0.009973404,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Провери покритие Провери покритие","depth":11,"bounds":{"left":0.5962433,"top":0.40223464,"width":0.07662899,"height":0.04030327},"on_screen":true,"help_text":"Провери покритие","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Провери покритие","depth":13,"bounds":{"left":0.6087101,"top":0.41340783,"width":0.051861703,"height":0.017956903},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Провери покритие","depth":13,"bounds":{"left":0.6087101,"top":0.4293695,"width":0.051861703,"height":0.017956903},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"FiberNet XΧL","depth":12,"bounds":{"left":0.69082445,"top":0.14844373,"width":0.07795878,"height":0.037110932},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"FiberNet XΧL","depth":13,"bounds":{"left":0.69082445,"top":0.14764565,"width":0.0546875,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"до 2, 000 Mbps за download до 1, 000 Mbps за upload","depth":12,"bounds":{"left":0.70146275,"top":0.20151636,"width":0.06732048,"height":0.054269753},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"до 2, 000 Mbps","depth":13,"bounds":{"left":0.70146275,"top":0.20111732,"width":0.04870346,"height":0.021947326},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"за download","depth":13,"bounds":{"left":0.70146275,"top":0.22186752,"width":0.031083776,"height":0.017956903},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"до 1, 000 Mbps за upload","depth":13,"bounds":{"left":0.70146275,"top":0.23822825,"width":0.061170213,"height":0.017956903},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Безплатен Wi-Fi рутер","depth":12,"bounds":{"left":0.70146275,"top":0.26536313,"width":0.06732048,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Безплатен Wi-Fi рутер","depth":13,"bounds":{"left":0.70146275,"top":0.26456505,"width":0.05435505,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Повече детайли","depth":12,"bounds":{"left":0.69082445,"top":0.29768556,"width":0.049867023,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Повече детайли","depth":13,"bounds":{"left":0.70212764,"top":0.29688746,"width":0.03856383,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"13.94€","depth":14,"bounds":{"left":0.69082445,"top":0.3347965,"width":0.028424202,"height":0.030726258},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"|","depth":14,"bounds":{"left":0.720246,"top":0.3347965,"width":0.0023271276,"height":0.030726258},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"27.26лв.","depth":14,"bounds":{"left":0.7237367,"top":0.3347965,"width":0.036070477,"height":0.030726258},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/мес.","depth":14,"bounds":{"left":0.75980717,"top":0.34836394,"width":0.008976064,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"след 2 месеца 27.90€ | 54.57лв.","depth":13,"bounds":{"left":0.69082445,"top":0.36472467,"width":0.06781915,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/мес.","depth":13,"bounds":{"left":0.7586436,"top":0.36632082,"width":0.009973404,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Провери покритие Провери покритие","depth":11,"bounds":{"left":0.69082445,"top":0.40223464,"width":0.07795878,"height":0.04030327},"on_screen":true,"help_text":"Провери покритие","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Провери покритие","depth":13,"bounds":{"left":0.7037899,"top":0.41340783,"width":0.051861703,"height":0.017956903},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Провери покритие","depth":13,"bounds":{"left":0.7037899,"top":0.4293695,"width":0.051861703,"height":0.017956903},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"FiberNet 10G","depth":12,"bounds":{"left":0.78673536,"top":0.14844373,"width":0.0859375,"height":0.037110932},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"FiberNet 10G","depth":13,"bounds":{"left":0.78673536,"top":0.14764565,"width":0.054521278,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"10, 000 Mbps max download speed 2, 000 Mbps max upload speed","depth":12,"bounds":{"left":0.79737365,"top":0.20151636,"width":0.0752992,"height":0.054269753},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"10, 000 Mbps","depth":13,"bounds":{"left":0.79737365,"top":0.20111732,"width":0.042386968,"height":0.021947326},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"max download speed","depth":13,"bounds":{"left":0.79737365,"top":0.22186752,"width":0.051529255,"height":0.017956903},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2, 000 Mbps max upload speed","depth":13,"bounds":{"left":0.79737365,"top":0.23822825,"width":0.0752992,"height":0.017956903},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Повече детайли","depth":12,"bounds":{"left":0.78673536,"top":0.2669593,"width":0.049867023,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Повече детайли","depth":13,"bounds":{"left":0.79803854,"top":0.26656026,"width":0.03856383,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"38.45€","depth":14,"bounds":{"left":0.78673536,"top":0.3347965,"width":0.029587766,"height":0.030726258},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"|","depth":14,"bounds":{"left":0.8174867,"top":0.3347965,"width":0.0023271276,"height":0.030726258},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"75.20лв.","depth":14,"bounds":{"left":0.82081115,"top":0.3347965,"width":0.03656915,"height":0.030726258},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/мес.","depth":14,"bounds":{"left":0.85738033,"top":0.34836394,"width":0.00880984,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"след 2 месеца 76.90€ | 150.40лв.","depth":13,"bounds":{"left":0.78673536,"top":0.36472467,"width":0.0709774,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/мес.","depth":13,"bounds":{"left":0.85771275,"top":0.36632082,"width":0.009807181,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Провери покритие Провери покритие","depth":11,"bounds":{"left":0.78673536,"top":0.40223464,"width":0.0859375,"height":0.04030327},"on_screen":true,"help_text":"Провери покритие","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Провери покритие","depth":13,"bounds":{"left":0.80369014,"top":0.41340783,"width":0.052027926,"height":0.017956903},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Провери покритие","depth":13,"bounds":{"left":0.80369014,"top":0.4293695,"width":0.052027926,"height":0.017956903},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"ПОЛЗИ","depth":9,"bounds":{"left":0.6722075,"top":0.5071828,"width":0.03025266,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ПОЛЗИ","depth":10,"bounds":{"left":0.6761968,"top":0.5067837,"width":0.022273935,"height":0.021947326},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Супер бърза интернет скорост","depth":12,"bounds":{"left":0.5518617,"top":0.6340782,"width":0.061170213,"height":0.037110932},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Безплатен Wi-Fi рутер","depth":12,"bounds":{"left":0.65724736,"top":0.6340782,"width":0.059840426,"height":0.017956903},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"24/7 техническа поддръжка","depth":12,"bounds":{"left":0.75598407,"top":0.6340782,"width":0.072140954,"height":0.017956903},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Допълнителни услуги","depth":11,"bounds":{"left":0.4878657,"top":0.74860334,"width":0.06000665,"height":0.017956903},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Антивирусна програма","depth":10,"bounds":{"left":0.4878657,"top":0.80407023,"width":0.09607713,"height":0.026735835},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0 € | 0 лв.","depth":11,"bounds":{"left":0.829621,"top":0.8028731,"width":0.04504654,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/мес.","depth":11,"bounds":{"left":0.8746675,"top":0.8164405,"width":0.012134309,"height":0.017956903},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Статичен IP адрес","depth":10,"bounds":{"left":0.4878657,"top":0.8719074,"width":0.078457445,"height":0.026735835},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1.02 € | 1.99 лв.","depth":11,"bounds":{"left":0.80418885,"top":0.8707103,"width":0.07047872,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/мес.","depth":11,"bounds":{"left":0.8746675,"top":0.88427776,"width":0.012134309,"height":0.017956903},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Close","depth":9,"bounds":{"left":0.9087433,"top":0.23743017,"width":0.005319149,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Богомил Райнов 4, 1000 София","depth":10,"bounds":{"left":0.6263298,"top":0.3084597,"width":0.12200798,"height":0.026336791},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Въведете друг адрес","depth":9,"bounds":{"left":0.65957445,"top":0.33719075,"width":0.055518616,"height":0.016759777},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Въведете друг адрес","depth":10,"bounds":{"left":0.65957445,"top":0.3367917,"width":0.055518616,"height":0.017956903},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"НАЛИЧНИ ИНТЕРНЕТ ПЛАНОВЕ","depth":10,"bounds":{"left":0.6334774,"top":0.39225858,"width":0.10771277,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"НАЛИЧНИ ИНТЕРНЕТ ПЛАНОВЕ","depth":11,"bounds":{"left":0.6374667,"top":0.3914605,"width":0.099734046,"height":0.021947326},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"FiberNet L","depth":12,"bounds":{"left":0.55369014,"top":0.46488428,"width":0.07646277,"height":0.037110932},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"FiberNet L","depth":13,"bounds":{"left":0.55369014,"top":0.4640862,"width":0.043218084,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"до 200 Mbps за download до 100 Mbps за upload","depth":12,"bounds":{"left":0.56432843,"top":0.5179569,"width":0.06582447,"height":0.054269753},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"до 200 Mbps","depth":13,"bounds":{"left":0.56432843,"top":0.51755786,"width":0.04105718,"height":0.021947326},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"за download","depth":13,"bounds":{"left":0.56432843,"top":0.5383081,"width":0.03125,"height":0.017956903},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"до 100 Mbps за upload","depth":13,"bounds":{"left":0.56432843,"top":0.5546688,"width":0.055684842,"height":0.017956903},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Безплатен Wi-Fi рутер","depth":12,"bounds":{"left":0.56432843,"top":0.5818037,"width":0.06582447,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Безплатен Wi-Fi рутер","depth":13,"bounds":{"left":0.56432843,"top":0.5810056,"width":0.05435505,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5.95€","depth":15,"bounds":{"left":0.55369014,"top":0.61851555,"width":0.02443484,"height":0.030726258},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"|","depth":15,"bounds":{"left":0.57912236,"top":0.61851555,"width":0.002493351,"height":0.030726258},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"11.64лв.","depth":15,"bounds":{"left":0.58261305,"top":0.61851555,"width":0.03357713,"height":0.030726258},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/мес.","depth":15,"bounds":{"left":0.61619014,"top":0.632083,"width":0.008976064,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"след 2 месеца 11.90€ | 23.27лв.","depth":14,"bounds":{"left":0.55369014,"top":0.64844376,"width":0.06665558,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/мес.","depth":14,"bounds":{"left":0.6203458,"top":0.6500399,"width":0.009807181,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Поръчай Поръчай","depth":12,"bounds":{"left":0.55369014,"top":0.68595374,"width":0.07646277,"height":0.040702313},"on_screen":true,"help_text":"Поръчай","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Поръчай","depth":14,"bounds":{"left":0.58045214,"top":0.6971269,"width":0.023105053,"height":0.017956903},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Поръчай","depth":14,"bounds":{"left":0.58045214,"top":0.7130886,"width":0.023105053,"height":0.017956903},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Избран план","depth":13,"bounds":{"left":0.67370343,"top":0.43256184,"width":0.025265958,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"FiberNet XL","depth":12,"bounds":{"left":0.648105,"top":0.46488428,"width":0.07646277,"height":0.037110932},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"FiberNet XL","depth":13,"bounds":{"left":0.648105,"top":0.4640862,"width":0.049035903,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"до 600 Mbps за download до 400 Mbps за upload","depth":12,"bounds":{"left":0.6587433,"top":0.5179569,"width":0.06582447,"height":0.054269753},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"до 600 Mbps","depth":13,"bounds":{"left":0.6587433,"top":0.51755786,"width":0.041223403,"height":0.021947326},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"за download","depth":13,"bounds":{"left":0.6587433,"top":0.5383081,"width":0.03125,"height":0.017956903},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"до 400 Mbps за upload","depth":13,"bounds":{"left":0.6587433,"top":0.5546688,"width":0.05668218,"height":0.017956903},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Безплатен Wi-Fi рутер","depth":12,"bounds":{"left":0.6587433,"top":0.5818037,"width":0.06582447,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Безплатен Wi-Fi рутер","depth":13,"bounds":{"left":0.6587433,"top":0.5810056,"width":0.05435505,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"8.95€","depth":15,"bounds":{"left":0.648105,"top":0.61851555,"width":0.024601065,"height":0.030726258},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"|","depth":15,"bounds":{"left":0.67386967,"top":0.61851555,"width":0.0023271276,"height":0.030726258},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"17.50лв.","depth":15,"bounds":{"left":0.6771942,"top":0.61851555,"width":0.03507314,"height":0.030726258},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/мес.","depth":15,"bounds":{"left":0.7122673,"top":0.632083,"width":0.008976064,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"след 2 месеца 17.90€ | 35.01лв.","depth":14,"bounds":{"left":0.648105,"top":0.64844376,"width":0.06665558,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/мес.","depth":14,"bounds":{"left":0.71476066,"top":0.6500399,"width":0.009807181,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Поръчай Поръчай","depth":12,"bounds":{"left":0.648105,"top":0.68595374,"width":0.07646277,"height":0.040702313},"on_screen":true,"help_text":"Поръчай","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Поръчай","depth":14,"bounds":{"left":0.67486703,"top":0.6971269,"width":0.023105053,"height":0.017956903},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Поръчай","depth":14,"bounds":{"left":0.67486703,"top":0.7130886,"width":0.023105053,"height":0.017956903},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"FiberNet 1000","depth":12,"bounds":{"left":0.74252,"top":0.46488428,"width":0.078457445,"height":0.037110932},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"FiberNet 1000","depth":13,"bounds":{"left":0.74252,"top":0.4640862,"width":0.059840426,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"до 1000 Mbps за download до 700 Mbps за upload","depth":12,"bounds":{"left":0.7531583,"top":0.5179569,"width":0.06781915,"height":0.054269753},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"до 1000 Mbps","depth":13,"bounds":{"left":0.7531583,"top":0.51755786,"width":0.04438165,"height":0.021947326},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"за download","depth":13,"bounds":{"left":0.7531583,"top":0.5383081,"width":0.03125,"height":0.017956903},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"до 700 Mbps за upload","depth":13,"bounds":{"left":0.7531583,"top":0.5546688,"width":0.056349736,"height":0.017956903},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Безплатен Wi-Fi рутер","depth":12,"bounds":{"left":0.7531583,"top":0.5818037,"width":0.06781915,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Безплатен Wi-Fi рутер","depth":13,"bounds":{"left":0.7531583,"top":0.5810056,"width":0.05435505,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"10.69€","depth":15,"bounds":{"left":0.74252,"top":0.61851555,"width":0.029089095,"height":0.030726258},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"|","depth":15,"bounds":{"left":0.7726064,"top":0.61851555,"width":0.0023271276,"height":0.030726258},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"20.91лв.","depth":15,"bounds":{"left":0.77609706,"top":0.61851555,"width":0.035904255,"height":0.030726258},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/мес.","depth":15,"bounds":{"left":0.81200135,"top":0.632083,"width":0.008976064,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"след 2 месеца 21.37€ | 41.80лв.","depth":14,"bounds":{"left":0.74252,"top":0.64844376,"width":0.06632314,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/мес.","depth":14,"bounds":{"left":0.8088431,"top":0.6500399,"width":0.009807181,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Поръчай Поръчай","depth":12,"bounds":{"left":0.74252,"top":0.68595374,"width":0.078457445,"height":0.040702313},"on_screen":true,"help_text":"Поръчай","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Поръчай","depth":14,"bounds":{"left":0.7702792,"top":0.6971269,"width":0.022938829,"height":0.017956903},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Поръчай","depth":14,"bounds":{"left":0.7702792,"top":0.7130886,"width":0.022938829,"height":0.017956903},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Компанията","depth":8,"bounds":{"left":0.517121,"top":1.0,"width":0.080119684,"height":-0.034317613},"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Компанията","depth":9,"bounds":{"left":0.517121,"top":1.0,"width":0.05069814,"height":-0.03391862},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"За нас","depth":10,"bounds":{"left":0.517121,"top":1.0,"width":0.01412899,"height":-0.073822856},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"За нас","depth":11,"bounds":{"left":0.517121,"top":1.0,"width":0.01412899,"height":-0.07342374},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Етика и съответствие","depth":10,"bounds":{"left":0.517121,"top":1.0,"width":0.0546875,"height":-0.09696722},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Етика и съответствие","depth":11,"bounds":{"left":0.517121,"top":1.0,"width":0.0546875,"height":-0.09656823},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Марката Vivacom","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Марката Vivacom","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Мениджмънт","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Мениджмънт","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Социална отговорност","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Социална отговорност","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Новини","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Новини","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Кариери","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Кариери","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Доставчици","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Доставчици","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Доклад за устойчиво развитие","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Доклад за устойчиво развитие","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Частни клиенти","depth":8,"bounds":{"left":0.6022274,"top":1.0,"width":0.080119684,"height":-0.034317613},"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Частни клиенти","depth":9,"bounds":{"left":0.6022274,"top":1.0,"width":0.06781915,"height":-0.03391862},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Мобилни планове","depth":10,"bounds":{"left":0.6022274,"top":1.0,"width":0.03939495,"height":-0.073822856},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Мобилни планове","depth":11,"bounds":{"left":0.6022274,"top":1.0,"width":0.03939495,"height":-0.07342374},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Мобилен интернет","depth":10,"bounds":{"left":0.6022274,"top":1.0,"width":0.045212764,"height":-0.09696722},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Мобилен интернет","depth":11,"bounds":{"left":0.6022274,"top":1.0,"width":0.045212764,"height":-0.09656823},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Устройства","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Устройства","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Интернет пакети","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Интернет пакети","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Програма Лоялен клиент","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Програма Лоялен клиент","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Правила и условия","depth":8,"bounds":{"left":0.68733376,"top":1.0,"width":0.080119684,"height":-0.034317613},"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Правила и условия","depth":9,"bounds":{"left":0.68733376,"top":1.0,"width":0.07330452,"height":-0.03391862},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Общи условия","depth":10,"bounds":{"left":0.68733376,"top":1.0,"width":0.03174867,"height":-0.073822856},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Общи условия","depth":11,"bounds":{"left":0.68733376,"top":1.0,"width":0.03174867,"height":-0.07342374},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Мобилно покритие","depth":10,"bounds":{"left":0.68733376,"top":1.0,"width":0.043716755,"height":-0.09696722},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Мобилно покритие","depth":11,"bounds":{"left":0.68733376,"top":1.0,"width":0.043716755,"height":-0.09656823},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Лични данни","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Лични данни","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Правила за ползване","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Правила за ползване","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Роуминг","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Роуминг","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Политика за бисквитките","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Политика за бисквитките","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Полезни връзки","depth":8,"bounds":{"left":0.77244014,"top":1.0,"width":0.080119684,"height":-0.034317613},"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Полезни връзки","depth":9,"bounds":{"left":0.77244014,"top":1.0,"width":0.064328454,"height":-0.03391862},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Устройство в сервиз","depth":10,"bounds":{"left":0.77244014,"top":1.0,"width":0.050033245,"height":-0.073822856},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Устройство в сервиз","depth":11,"bounds":{"left":0.77244014,"top":1.0,"width":0.050033245,"height":-0.07342374},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Спешни номера","depth":10,"bounds":{"left":0.77244014,"top":1.0,"width":0.036070477,"height":-0.09696722},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Спешни номера","depth":11,"bounds":{"left":0.77244014,"top":1.0,"width":0.036070477,"height":-0.09656823},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Активиране на EON TV","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Активиране на EON TV","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Настройки на CA модул","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Настройки на CA модул","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Застраховки","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Застраховки","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Планове за хора с увреждания","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Планове за хора с увреждания","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Достъпност на сайта","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Достъпност на сайта","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Електронни фактури","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Електронни фактури","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"EUR BGN","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Валутен курс: 1 EUR = 1.95583 лв.","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"© VIVACOM 2026","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"google app - целевият уебсайт може да не е наличен","depth":8,"on_screen":false,"help_text":"Google app","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"App store - отвори в нов раздел","depth":8,"on_screen":false,"help_text":"App store","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Huawei store - отвори в нов раздел","depth":8,"on_screen":false,"help_text":"Huawei store","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Facebook","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"TikTok","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"YouTube","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Instagram","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Linkedin","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"United group - отвори в нов раздел","depth":8,"on_screen":false,"help_text":"United group","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Отворена джаджа за чат","depth":9,"bounds":{"left":0.9734042,"top":0.93615323,"width":0.021276595,"height":0.051077414},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":11,"bounds":{"left":0.9906915,"top":0.9357542,"width":0.0016622341,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Open CMP widget","depth":7,"bounds":{"left":0.37799203,"top":0.9537111,"width":0.015957447,"height":0.03830806},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false}]...
|
7597943172252136763
|
-3871944966500170209
|
visual_change
|
accessibility
|
NULL
|
Pull requests · screenpipe/screenpipe · GitHub
Pul Pull requests · screenpipe/screenpipe · GitHub
Pull requests · screenpipe/screenpipe · GitHub
Home | Hostinger
Home | Hostinger
Login – Nginx Proxy Manager
Login – Nginx Proxy Manager
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Премини към основното съдържание
Активиране на достъпност за хора със слабо зрение
Отворете менюто за достъпност
ЧАСТНИ КЛИЕНТИ
ЧАСТНИ КЛИЕНТИ
БИЗНЕС КЛИЕНТИ
БИЗНЕС КЛИЕНТИ
МАГАЗИНИ
МАГАЗИНИ
ГЛЕДАЙ EON
ГЛЕДАЙ EON
КОНТАКТИ
КОНТАКТИ
ОБЩИ УСЛОВИЯ
ОБЩИ УСЛОВИЯ
КАРТИ НА ПОКРИТИЕТО
КАРТИ НА ПОКРИТИЕТО
Vivacom Logo
Мобилни услуги
Мобилни услуги
Устройства
Устройства
EON
EON
Интернет
Интернет
Други услуги
Други услуги
Помощ
Помощ
Cart
Оптичен интернет
Оптичен интернет
Вземи Fiber с
50% отстъпка
за първите 2 месеца
и получаваш безплатен Wi-Fi 6 рутер.
Оптичен интернет Интернет за отдалечени места
Оптичен интернет
Интернет за
отдалечени места
ОПТИЧЕН ИНТЕРНЕТ
ОПТИЧЕН ИНТЕРНЕТ
FiberNet L
FiberNet L
до 200 Mbps за download до 100 Mbps за upload
до 200 Mbps
за download
до 100 Mbps за upload
Безплатен Wi-Fi рутер
Безплатен Wi-Fi рутер
Повече детайли
Повече детайли
6.60€
|
12.91лв.
/мес.
след 2 месеца 13.19€ | 25.80лв.
/мес.
Провери покритие Провери покритие
Провери покритие
Провери покритие
Най-продаван
FiberNet XL
FiberNet XL
до 600 Mbps за download до 400 Mbps за upload
до 600 Mbps
за download
до 400 Mbps за upload
Безплатен Wi-Fi рутер
Безплатен Wi-Fi рутер
Повече детайли
Повече детайли
8.95€
|
17.50лв.
/мес.
след 2 месеца 17.90€ | 35.01лв.
/мес.
Провери покритие Провери покритие
Провери покритие
Провери покритие
FiberNet XΧL
FiberNet XΧL
до 2, 000 Mbps за download до 1, 000 Mbps за upload
до 2, 000 Mbps
за download
до 1, 000 Mbps за upload
Безплатен Wi-Fi рутер
Безплатен Wi-Fi рутер
Повече детайли
Повече детайли
13.94€
|
27.26лв.
/мес.
след 2 месеца 27.90€ | 54.57лв.
/мес.
Провери покритие Провери покритие
Провери покритие
Провери покритие
FiberNet 10G
FiberNet 10G
10, 000 Mbps max download speed 2, 000 Mbps max upload speed
10, 000 Mbps
max download speed
2, 000 Mbps max upload speed
Повече детайли
Повече детайли
38.45€
|
75.20лв.
/мес.
след 2 месеца 76.90€ | 150.40лв.
/мес.
Провери покритие Провери покритие
Провери покритие
Провери покритие
ПОЛЗИ
ПОЛЗИ
Супер бърза интернет скорост
Безплатен Wi-Fi рутер
24/7 техническа поддръжка
Допълнителни услуги
Антивирусна програма
0 € | 0 лв.
/мес.
Статичен IP адрес
1.02 € | 1.99 лв.
/мес.
Close
Богомил Райнов 4, 1000 София
Въведете друг адрес
Въведете друг адрес
НАЛИЧНИ ИНТЕРНЕТ ПЛАНОВЕ
НАЛИЧНИ ИНТЕРНЕТ ПЛАНОВЕ
FiberNet L
FiberNet L
до 200 Mbps за download до 100 Mbps за upload
до 200 Mbps
за download
до 100 Mbps за upload
Безплатен Wi-Fi рутер
Безплатен Wi-Fi рутер
5.95€
|
11.64лв.
/мес.
след 2 месеца 11.90€ | 23.27лв.
/мес.
Поръчай Поръчай
Поръчай
Поръчай
Избран план
FiberNet XL
FiberNet XL
до 600 Mbps за download до 400 Mbps за upload
до 600 Mbps
за download
до 400 Mbps за upload
Безплатен Wi-Fi рутер
Безплатен Wi-Fi рутер
8.95€
|
17.50лв.
/мес.
след 2 месеца 17.90€ | 35.01лв.
/мес.
Поръчай Поръчай
Поръчай
Поръчай
FiberNet 1000
FiberNet 1000
до 1000 Mbps за download до 700 Mbps за upload
до 1000 Mbps
за download
до 700 Mbps за upload
Безплатен Wi-Fi рутер
Безплатен Wi-Fi рутер
10.69€
|
20.91лв.
/мес.
след 2 месеца 21.37€ | 41.80лв.
/мес.
Поръчай Поръчай
Поръчай
Поръчай
Компанията
Компанията
За нас
За нас
Етика и съответствие
Етика и съответствие
Марката Vivacom
Марката Vivacom
Мениджмънт
Мениджмънт
Социална отговорност
Социална отговорност
Новини
Новини
Кариери
Кариери
Доставчици
Доставчици
Доклад за устойчиво развитие
Доклад за устойчиво развитие
Частни клиенти
Частни клиенти
Мобилни планове
Мобилни планове
Мобилен интернет
Мобилен интернет
Устройства
Устройства
Интернет пакети
Интернет пакети
Програма Лоялен клиент
Програма Лоялен клиент
Правила и условия
Правила и условия
Общи условия
Общи условия
Мобилно покритие
Мобилно покритие
Лични данни
Лични данни
Правила за ползване
Правила за ползване
Роуминг
Роуминг
Политика за бисквитките
Политика за бисквитките
Полезни връзки
Полезни връзки
Устройство в сервиз
Устройство в сервиз
Спешни номера
Спешни номера
Активиране на EON TV
Активиране на EON TV
Настройки на CA модул
Настройки на CA модул
Застраховки
Застраховки
Планове за хора с увреждания
Планове за хора с увреждания
Достъпност на сайта
Достъпност на сайта
Електронни фактури
Електронни фактури
EUR BGN
Валутен курс: 1 EUR = 1.95583 лв.
© VIVACOM 2026
google app - целевият уебсайт може да не е наличен
App store - отвори в нов раздел
Huawei store - отвори в нов раздел
Facebook
TikTok
YouTube
Instagram
Linkedin
United group - отвори в нов раздел
Отворена джаджа за чат
1
Open CMP widget...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
9398
|
424
|
43
|
2026-05-08T12:45:56.025866+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778244356025_m2.jpg...
|
Firefox
|
Jy 20820 es reindex stream model hydration by Vasi Jy 20820 es reindex stream model hydration by Vasil-Jiminny · Pull Request #12059 · jiminny/app — Work...
|
True
|
github.com/jiminny/app/pull/12059/changes#diff-f77 github.com/jiminny/app/pull/12059/changes#diff-f77c5793308caa3e764a033422493121a1329dd953a89f3dde4a9386622f22f9...
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 3 Q2 - Platform Team - Scrum Board Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Unnamed Group
SevenShores\Hubspot\Exceptions\BadRequest: Client error: `POST [URL_WITH_CREDENTIALS] -5,69 +5,64 @@5namespace Jiminny\Component\ES\Processor\Actions;5namespace Jiminny\Component\ES\Processor\Actions;667use Elastica\Document;7use Elastica\Document;8-use Illuminate\Support\Collection;9use Jiminny\Component\ElasticSearch\Contract\Searchable;8use Jiminny\Component\ElasticSearch\Contract\Searchable;10use Jiminny\Component\ES\Processor\DTOs\DocumentLoad;9use Jiminny\Component\ES\Processor\DTOs\DocumentLoad;11use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;10use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;12use Jiminny\Component\ES\Processor\EntityQueryBuilder;11use Jiminny\Component\ES\Processor\EntityQueryBuilder;13-use Jiminny\Component\ES\Processor\Traits\SkipActivityTrait;14use Jiminny\Exceptions\SyncActivityException;12use Jiminny\Exceptions\SyncActivityException;15use Jiminny\Models\Model;13use Jiminny\Models\Model;16use Sentry\Laravel\Facade as Sentry;14use Sentry\Laravel\Facade as Sentry;15+use Throwable;171618class LoadDocumentsAction17class LoadDocumentsAction19{18{20-use SkipActivityTrait;19+public function __construct(21-20+private readonly EntityQueryBuilder $queryBuilder22-private const int RDS_CHUNK_SIZE = 250;21+ ) {22+ }232324-/**25- * @codeCoverageIgnore26- */27public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad24public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad28 {25 {29$documentsToUpdate = new SimpleCollection();26$documentsToUpdate = new SimpleCollection();30$documentsToDelete = new SimpleCollection();27$documentsToDelete = new SimpleCollection();312832-// do get mariadb data29+$query = $this->queryBuilder->getEntityQuery($updateTarget, $entityIdsList);33-$query = EntityQueryBuilder::getEntityQuery($updateTarget, $entityIdsList);343035-$query->chunkByIdDesc(31+/** @var Model&Searchable $entityModel */36-self::RDS_CHUNK_SIZE,32+foreach ($query->cursor() as $entityModel) {37-function (Collection $entityModels) use ($documentsToUpdate, $documentsToDelete) {33+if ($entityModel->isDeleted()) {38-/** @var Model&Searchable $entityForDeletion */34+/**39-foreach ($entityModels->whereNotNull('deleted_at') as $entityForDeletion) {35+ * Cleanup (from ElasticSearch) scheduled entities that were recently deleted.40-$documentsToDelete->add($entityForDeletion->getId());36+ * After a deletion, no more updates on a record are expected, so the operation is considered final,41- }37+ * unless the record is restored.42-38+ */43-/** @var Model&Searchable $entityModel */39+$documentsToDelete->add($entityModel->getId());44-foreach ($entityModels->whereNull('deleted_at') as $entityModel) {40+ } else {45-if (self::shouldSkipActivity($entityModel)) {41+try {46-/**42+$documentsToUpdate->add(47- * If the activity type is in the skip list, we should not push it for indexing.43+new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())48- * If an ES record already exists, we should remove it to free up storage and processing power44+ );49- */45+ } catch (Throwable $error) {50-$documentsToDelete->add($entityModel->getId());46+ Sentry::captureException(51-47+new SyncActivityException(52-continue;48+'ES entity async RDS build data failed',53- }49+$error->getCode(),54-50+$error55-try {51+ )56-$documentsToUpdate->add(52+ );57-new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())58- );59- } catch (\Throwable $error) {60- Sentry::captureException(61-new SyncActivityException(62-'ES entity async RDS build data failed',63-$error->getCode(),64-$error65- )66- );67- }68 }53 }69 }54 }70- );55+56+/**57+ * Clean up fragmented memory.58+ * Dropping relations and unsetting the entity model after hydration and usage,59+ * allows GC to remove heap memory allocations, and recycle already allocated memory,60+ * instead of allocating more memory from OS.61+ * Unset operations signal GC to collect destroyed object memory62+ */63+$entityModel->setRelations([]);64+ unset($entityModel);65+ }716672return new DocumentLoad($documentsToUpdate, $documentsToDelete);67return new DocumentLoad($documentsToUpdate, $documentsToDelete);73 }68 }</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>Jy 20820 es reindex stream model hydration by Vasi</tabTitle>” with “<selection>@@ -5,69 +5,64 @@5namespace Jiminny\Component\ES\Processor\Actions;5namespace Jiminny\Component\ES\Processor\Actions;667use Elastica\Document;7use Elastica\Document;8-use Illuminate\Support\Collection;9use Jiminny\Component\ElasticSearch\Contract\Searchable;8use Jiminny\Component\ElasticSearch\Contract\Searchable;10use Jiminny\Component\ES\Processor\DTOs\DocumentLoad;9use Jiminny\Component\ES\Processor\DTOs\DocumentLoad;11use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;10use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;12use Jiminny\Component\ES\Processor\EntityQueryBuilder;11use Jiminny\Component\ES\Processor\EntityQueryBuilder;13-use Jiminny\Component\ES\Processor\Traits\SkipActivityTrait;14use Jiminny\Exceptions\SyncActivityException;12use Jiminny\Exceptions\SyncActivityException;15use Jiminny\Models\Model;13use Jiminny\Models\Model;16use Sentry\Laravel\Facade as Sentry;14use Sentry\Laravel\Facade as Sentry;15+use Throwable;171618class LoadDocumentsAction17class LoadDocumentsAction19{18{20-use SkipActivityTrait;19+public function __construct(21-20+private readonly EntityQueryBuilder $queryBuilder22-private const int RDS_CHUNK_SIZE = 250;21+ ) {22+ }232324-/**25- * @codeCoverageIgnore26- */27public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad24public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad28 {25 {29$documentsToUpdate = new SimpleCollection();26$documentsToUpdate = new SimpleCollection();30$documentsToDelete = new SimpleCollection();27$documentsToDelete = new SimpleCollection();312832-// do get mariadb data29+$query = $this->queryBuilder->getEntityQuery($updateTarget, $entityIdsList);33-$query = EntityQueryBuilder::getEntityQuery($updateTarget, $entityIdsList);343035-$query->chunkByIdDesc(31+/** @var Model&Searchable $entityModel */36-self::RDS_CHUNK_SIZE,32+foreach ($query->cursor() as $entityModel) {37-function (Collection $entityModels) use ($documentsToUpdate, $documentsToDelete) {33+if ($entityModel->isDeleted()) {38-/** @var Model&Searchable $entityForDeletion */34+/**39-foreach ($entityModels->whereNotNull('deleted_at') as $entityForDeletion) {35+ * Cleanup (from ElasticSearch) scheduled entities that were recently deleted.40-$documentsToDelete->add($entityForDeletion->getId());36+ * After a deletion, no more updates on a record are expected, so the operation is considered final,41- }37+ * unless the record is restored.42-38+ */43-/** @var Model&Searchable $entityModel */39+$documentsToDelete->add($entityModel->getId());44-foreach ($entityModels->whereNull('deleted_at') as $entityModel) {40+ } else {45-if (self::shouldSkipActivity($entityModel)) {41+try {46-/**42+$documentsToUpdate->add(47- * If the activity type is in the skip list, we should not push it for indexing.43+new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())48- * If an ES record already exists, we should remove it to free up storage and processing power44+ );49- */45+ } catch (Throwable $error) {50-$documentsToDelete->add($entityModel->getId());46+ Sentry::captureException(51-47+new SyncActivityException(52-continue;48+'ES entity async RDS build data failed',53- }49+$error->getCode(),54-50+$error55-try {51+ )56-$documentsToUpdate->add(52+ );57-new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())58- );59- } catch (\Throwable $error) {60- Sentry::captureException(61-new SyncActivityException(62-'ES entity async RDS build data failed',63-$error->getCode(),64-$error65- )66- );67- }68 }53 }69 }54 }70- );55+56+/**57+ * Clean up fragmented memory.58+ * Dropping relations and unsetting the entity model after hydration and usage,59+ * allows GC to remove heap memory allocations, and recycle already allocated memory,60+ * instead of allocating more memory from OS.61+ * Unset operations signal GC to collect destroyed object memory62+ */63+$entityModel->setRelations([]);64+ unset($entityModel);65+ }716672return new DocumentLoad($documentsToUpdate, $documentsToDelete);67return new DocumentLoad($documentsToUpdate, $documentsToDelete);73 }68 }</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Collapse
Listen
Show more options
Show thinking
Gemini said
Gemini said
Overview
Overview
This diff refactors the
LoadDocumentsAction
class to optimize memory usage and data processing. It transitions the database query execution from batch chunking to lazy loading using cursors, introduces explicit memory management techniques, and updates the class structure to use dependency injection.
Architectural & Structural Changes
Architectural & Structural Changes
Dependency Injection:
Injected
EntityQueryBuilder
via the constructor instead of calling it statically.
Removed Traits & Constants:
Removed the
SkipActivityTrait
entirely (and its associated skip logic), as well as the
RDS_CHUNK_SIZE
constant.
Namespace Imports:
Added the
Throwable
import and removed
Illuminate\Support\Collection
.
Data Processing Refactor
Data Processing Refactor
Cursor Implementation:
Replaced
chunkByIdDesc
with
cursor()
, iterating through records sequentially rather than loading batches of 250 into memory.
Simplified Deletion Checks:
Replaced Laravel collection filtering (
whereNotNull('deleted_at')
) with a direct
$entityModel->isDeleted()
check on each model during iteration.
Removed Skip Logic:
Removed the
shouldSkipActivity
check, meaning all non-deleted models are now directly processed for updates.
Exception Handling:
Updated the catch block to use the imported
Throwable
interface rather than the fully qualified
\Throwable
.
Memory Optimization
Memory Optimization
Explicit Garbage Collection:
Added specific cleanup steps inside the iteration loop. Dropping loaded relationships (
$entityModel->setRelations([])
) and unsetting the model (
unset($entityModel)
) explicitly signals the PHP Garbage Collector to free and recycle heap memory, preventing excessive OS memory allocation during large stream hydration.
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said You are seasoned code reviewer and your task is to make detailed code review of summarized page. First understand the code changes, then evaluate it and try to find potential issues and bottlenecks.
You said
You are seasoned code reviewer and your task is to make detailed code
review of summarized page. First understand the code changes, then
evaluate it and try to find potential issues and bottlenecks.
Expand
Listen
Show more options
Show thinking
Gemini said
Gemini said
Code Review: LoadDocumentsAction Refactoring
Code Review:
LoadDocumentsAction
Refactoring
As requested, I have reviewed the refactoring of the
LoadDocumentsAction
class. While the intent to modernize the architecture and optimize memory is clear, there are several critical architectural flaws and potential bottlenecks in the new implementation that need to be addressed before this goes to production.
Here is my detailed evaluation.
1. Strengths & Positive Changes
1. Strengths & Positive Changes
Dependency Injection:
Moving
EntityQueryBuilder
from a static call to an injected dependency significantly improves the testability of the class. You can now easily mock the query builder in your unit tests.
Simplified Readability:
Replacing the nested closures required by
chunkByIdDesc
with a flatter
foreach
structure makes the code easier to read and reason about.
Garbage Collection Awareness:
The developer is actively thinking about heap memory and Garbage Collection (GC), which is crucial for background workers and hydration scripts.
2. Critical Issues & Bottlenecks
2. Critical Issues & Bottlenecks
A. The "Infinite Accumulation" Memory Leak
A. The "Infinite Accumulation" Memory Leak
The primary goal of this refactor was memory optimization, but the implementation defeats its own purpose.
The Issue:
The code iterates over the database cursor and manually unsets
$entityModel
to free memory. However, it simultaneously instantiates new
Document
objects and adds them to
$documentsToUpdate
(and IDs to
$documentsToDelete
).
The Bottleneck:
These collections are not flushed or processed within the loop; they are accumulated and returned at the end of the method. If this script processes 500,000 records,
$documentsToUpdate
will hold 500,000 ElasticSearch
Document
objects in RAM at once, inevitably leading to an Out Of Memory (OOM) fatal error.
B. Laravel cursor() and N+1 Query Problems
B. Laravel
cursor()
and N+1 Query Problems
Replacing
chunkByIdDesc()
with
cursor()
introduces a severe database performance risk.
The Issue:
Laravel's
cursor()
executes a single query and uses a PHP generator to yield results one by one via a PDO cursor. Because it does not process models in batches,
cursor()
cannot eager-load relationships.
*
The Bottleneck:
If
$entityModel->getIndexableAttributes()
relies on
any
database relationships (e.g., getting a user's company or tags), it will trigger an N+1 query. For 100,000 records, this will execute 100,001 database queries, absolutely hammering the database.
C. Long-Running PDO Connections
C. Long-Running PDO Connections
The Issue:
Because
cursor()
keeps a single database connection open while iterating through the results, any network latency encountered inside the loop extends the transaction time.
The Bottleneck:
If ElasticSearch
Document
instantiation or the Sentry API calls (on failure) take time, the PDO connection to the MariaDB database will remain open for an extended period, potentially leading to connection timeouts, blocked processes, or database lock exhaustion.
3. Minor Issues & Observations
3. Minor Issues & Observations
Missing Skip Logic:
The removal of
SkipActivityTrait
assumes these models no longer need to be bypassed. If this was an accidental omission, you will end up polluting ElasticSearch with activity logs that were previously filtered out, wasting ES storage and processing power.
Synchronous Sentry Calls:
If a specific batch of data is malformed and throws multiple
Throwable
errors consecutively,
Sentry::captureException
will make synchronous outbound HTTP calls for every failed record. This will severely degrade the throughput of the hydration process.
4. Recommendations for Refactoring
4. Recommendations for Refactoring
To resolve these issues, I recommend a hybrid approach utilizing Laravel's
lazyById()
(or returning to chunking) combined with batch-processing the ElasticSearch payloads:
Use
lazyById()
instead of
cursor()
:
* Laravel's
lazyById(250)
fetches records in chunks under the hood (allowing for eager loading of relations without N+1) but yields them as a flat generator to the
foreach
loop. This gives you the clean syntax of a generator with the safety of chunked eager loading.
Dispatch to ElasticSearch Inside the Loop:
* Do not wait until the end of the method to return massive collections.
Keep a counter. When
$documentsToUpdate
reaches a certain threshold (e.g., 500 documents), dispatch them to ElasticSearch, empty the
SimpleCollection
, and continue the loop.
Group Sentry Exceptions:
Consider implementing a circuit breaker or batching error logs so that a sudden spike in formatting errors doesn't result in thousands of synchronous API calls to Sentry.
Good response
Bad response
Redo
Share & export
Copy
Show more options
Enter a prompt for Gemini
encrypted
Enter a prompt for Gemini
encrypted
Open upload file menu
Tools
Open mode picker
Pro
Microphone
Send message
Your Jiminny chats aren’t used to improve our models. Gemini is AI. It can make mistakes, so double check it.
Your privacy & Gemini Opens in a new window
Your privacy & Gemini
Opens in a new window
Summarize page
Summarize page
Skip to content
Skip to content
Open menu
Homepage (g then d)
jiminny
jiminny
app
app
Search or jump to…
Type
/
to search
Chat with Copilot
Open Copilot…
Create new...
All issues(g then i)
All pull requests
All repositories
You have unread notifications(g then n)
Open user navigation menu
Repository navigation
Repository navigation
Code
Code
Pull requests (33)
Pull requests
(
33
)
Agents
Agents
Actions
Actions
Wiki
Wiki
Security and quality (2)
Security and quality
(
2
)
Insights
Insights
Settings
Settings
Important update
Important update
On April 24 we'll start using GitHub Copilot interaction data for AI model training unless you opt out.
Review this update
Review this update
and manage your preferences in your
GitHub account settings
GitHub account settings
.
Dismiss banner
Jy 20820 es reindex stream model hydration #12059 Edit title
Jy 20820 es reindex stream model hydration
#
12059
Edit title
Preview
Preview
Awaiting approval
Awaiting approval
Code
Code
Open
Vasil-Jiminny
Vasil-Jiminny
wants to merge 35 commits into
master
master
from
JY-20820-es-reindex-stream-model-hydration
JY-20820-es-reindex-stream-model-hydration
Copy head branch name to clipboard
Lines changed: 363 additions & 140 deletions
Conversation (8)
Conversation
(
8
)
Commits (35)
Commits
(
35
)
Checks (3)
Checks
(
3...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.2237367,"top":0.0518755,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira","depth":5,"bounds":{"left":0.23703457,"top":0.06304868,"width":0.10106383,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Unnamed Group","depth":4,"bounds":{"left":0.2265625,"top":0.08978452,"width":0.007978723,"height":0.01915403},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXRadioButton","text":"SevenShores\\Hubspot\\Exceptions\\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your secondly limit.\",\"errorType\":\"RATE_LIMIT","depth":4,"bounds":{"left":0.2265625,"top":0.11332801,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SevenShores\\Hubspot\\Exceptions\\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your secondly limit.\",\"errorType\":\"RATE_LIMIT","depth":5,"bounds":{"left":0.23969415,"top":0.1245012,"width":0.4644282,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SevenShores\\Hubspot\\Exceptions\\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your secondly limit.\",\"errorType\":\"RATE_LIMIT","depth":4,"bounds":{"left":0.2265625,"top":0.14604948,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SevenShores\\Hubspot\\Exceptions\\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your secondly limit.\",\"errorType\":\"RATE_LIMIT","depth":5,"bounds":{"left":0.23969415,"top":0.15722266,"width":0.4644282,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Service-Desk - Queues - Platform team - Service space - Jira","depth":4,"bounds":{"left":0.2237367,"top":0.17877094,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Service-Desk - Queues - Platform team - Service space - Jira","depth":5,"bounds":{"left":0.23703457,"top":0.18994413,"width":0.10721409,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app","depth":4,"bounds":{"left":0.2237367,"top":0.21149242,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app","depth":5,"bounds":{"left":0.23703457,"top":0.22266561,"width":0.17037898,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Feed — jiminny — Sentry","depth":4,"bounds":{"left":0.2237367,"top":0.2442139,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Feed — jiminny — Sentry","depth":5,"bounds":{"left":0.23703457,"top":0.25538707,"width":0.042719416,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20818 move ask jiminny reports to its own datadog metric by LakyLak · Pull Request #12056 · jiminny/app","depth":4,"bounds":{"left":0.2237367,"top":0.27693537,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20818 move ask jiminny reports to its own datadog metric by LakyLak · Pull Request #12056 · jiminny/app","depth":5,"bounds":{"left":0.23703457,"top":0.28810853,"width":0.18899602,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Userpilot | Ask Jiminny Report Generated","depth":4,"bounds":{"left":0.2237367,"top":0.30965683,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Userpilot | Ask Jiminny Report Generated","depth":5,"bounds":{"left":0.23703457,"top":0.32083002,"width":0.07164229,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app","depth":4,"bounds":{"left":0.2237367,"top":0.3423783,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app","depth":5,"bounds":{"left":0.23703457,"top":0.35355148,"width":0.19331782,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Problem loading page","depth":4,"bounds":{"left":0.2237367,"top":0.37509975,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Problem loading page","depth":5,"bounds":{"left":0.23703457,"top":0.38627294,"width":0.037898935,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Search the CRM - HubSpot docs","depth":4,"bounds":{"left":0.2237367,"top":0.40782124,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Search the CRM - HubSpot docs","depth":5,"bounds":{"left":0.23703457,"top":0.41899443,"width":0.05651596,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"bounds":{"left":0.2237367,"top":0.4405427,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"bounds":{"left":0.23703457,"top":0.4517159,"width":0.013131649,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"New Tab","depth":4,"bounds":{"left":0.2237367,"top":0.47326416,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New Tab","depth":5,"bounds":{"left":0.23703457,"top":0.48443735,"width":0.014960106,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"New Tab","depth":4,"bounds":{"left":0.2237367,"top":0.5059856,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New Tab","depth":5,"bounds":{"left":0.23703457,"top":0.5171588,"width":0.014960106,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"AI Features | Datadog","depth":4,"bounds":{"left":0.2237367,"top":0.5387071,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AI Features | Datadog","depth":5,"bounds":{"left":0.23703457,"top":0.54988027,"width":0.037400264,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jy 20493 smart instant nudge pre filtering by nikolaybiaivanov · Pull Request #12053 · jiminny/app","depth":4,"bounds":{"left":0.2237367,"top":0.5714286,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jy 20493 smart instant nudge pre filtering by nikolaybiaivanov · Pull Request #12053 · jiminny/app","depth":5,"bounds":{"left":0.23703457,"top":0.5826017,"width":0.17037898,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Pipelines - jiminny/app","depth":4,"bounds":{"left":0.2237367,"top":0.60415006,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pipelines - jiminny/app","depth":5,"bounds":{"left":0.23703457,"top":0.61532325,"width":0.039228722,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jy 20820 es reindex stream model hydration by Vasil-Jiminny · Pull Request #12059 · jiminny/app","depth":4,"bounds":{"left":0.2237367,"top":0.6368715,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Jy 20820 es reindex stream model hydration by Vasil-Jiminny · Pull Request #12059 · jiminny/app","depth":5,"bounds":{"left":0.23703457,"top":0.6480447,"width":0.16888298,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.29105717,"top":0.6440543,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.2265625,"top":0.6711891,"width":0.07413564,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.2265625,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"bounds":{"left":0.23753324,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"bounds":{"left":0.2486702,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.25980717,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.27094415,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":7,"bounds":{"left":0.4084109,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":7,"bounds":{"left":0.42037898,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"WORK, Google Account: lukas.kovalik@jiminny.com","depth":12,"bounds":{"left":0.41771942,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Main menu","depth":12,"bounds":{"left":0.3073471,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Chat","depth":12,"bounds":{"left":0.38979387,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open menu for conversation actions.","depth":12,"bounds":{"left":0.40309176,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Conversation with Gemini","depth":15,"bounds":{"left":0.30302528,"top":0.14764565,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":16,"bounds":{"left":0.30302528,"top":0.15003991,"width":0.1200133,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy prompt","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said I’m on page “<tabTitle>Jy 20820 es reindex stream model hydration by Vasi</tabTitle>” with “<selection>@@ -5,69 +5,64 @@5namespace Jiminny\\Component\\ES\\Processor\\Actions;5namespace Jiminny\\Component\\ES\\Processor\\Actions;667use Elastica\\Document;7use Elastica\\Document;8-use Illuminate\\Support\\Collection;9use Jiminny\\Component\\ElasticSearch\\Contract\\Searchable;8use Jiminny\\Component\\ElasticSearch\\Contract\\Searchable;10use Jiminny\\Component\\ES\\Processor\\DTOs\\DocumentLoad;9use Jiminny\\Component\\ES\\Processor\\DTOs\\DocumentLoad;11use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;10use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;12use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;11use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;13-use Jiminny\\Component\\ES\\Processor\\Traits\\SkipActivityTrait;14use Jiminny\\Exceptions\\SyncActivityException;12use Jiminny\\Exceptions\\SyncActivityException;15use Jiminny\\Models\\Model;13use Jiminny\\Models\\Model;16use Sentry\\Laravel\\Facade as Sentry;14use Sentry\\Laravel\\Facade as Sentry;15+use Throwable;171618class LoadDocumentsAction17class LoadDocumentsAction19{18{20-use SkipActivityTrait;19+public function __construct(21-20+private readonly EntityQueryBuilder $queryBuilder22-private const int RDS_CHUNK_SIZE = 250;21+ ) {22+ }232324-/**25- * @codeCoverageIgnore26- */27public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad24public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad28 {25 {29$documentsToUpdate = new SimpleCollection();26$documentsToUpdate = new SimpleCollection();30$documentsToDelete = new SimpleCollection();27$documentsToDelete = new SimpleCollection();312832-// do get mariadb data29+$query = $this->queryBuilder->getEntityQuery($updateTarget, $entityIdsList);33-$query = EntityQueryBuilder::getEntityQuery($updateTarget, $entityIdsList);343035-$query->chunkByIdDesc(31+/** @var Model&Searchable $entityModel */36-self::RDS_CHUNK_SIZE,32+foreach ($query->cursor() as $entityModel) {37-function (Collection $entityModels) use ($documentsToUpdate, $documentsToDelete) {33+if ($entityModel->isDeleted()) {38-/** @var Model&Searchable $entityForDeletion */34+/**39-foreach ($entityModels->whereNotNull('deleted_at') as $entityForDeletion) {35+ * Cleanup (from ElasticSearch) scheduled entities that were recently deleted.40-$documentsToDelete->add($entityForDeletion->getId());36+ * After a deletion, no more updates on a record are expected, so the operation is considered final,41- }37+ * unless the record is restored.42-38+ */43-/** @var Model&Searchable $entityModel */39+$documentsToDelete->add($entityModel->getId());44-foreach ($entityModels->whereNull('deleted_at') as $entityModel) {40+ } else {45-if (self::shouldSkipActivity($entityModel)) {41+try {46-/**42+$documentsToUpdate->add(47- * If the activity type is in the skip list, we should not push it for indexing.43+new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())48- * If an ES record already exists, we should remove it to free up storage and processing power44+ );49- */45+ } catch (Throwable $error) {50-$documentsToDelete->add($entityModel->getId());46+ Sentry::captureException(51-47+new SyncActivityException(52-continue;48+'ES entity async RDS build data failed',53- }49+$error->getCode(),54-50+$error55-try {51+ )56-$documentsToUpdate->add(52+ );57-new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())58- );59- } catch (\\Throwable $error) {60- Sentry::captureException(61-new SyncActivityException(62-'ES entity async RDS build data failed',63-$error->getCode(),64-$error65- )66- );67- }68 }53 }69 }54 }70- );55+56+/**57+ * Clean up fragmented memory.58+ * Dropping relations and unsetting the entity model after hydration and usage,59+ * allows GC to remove heap memory allocations, and recycle already allocated memory,60+ * instead of allocating more memory from OS.61+ * Unset operations signal GC to collect destroyed object memory62+ */63+$entityModel->setRelations([]);64+ unset($entityModel);65+ }716672return new DocumentLoad($documentsToUpdate, $documentsToDelete);67return new DocumentLoad($documentsToUpdate, $documentsToDelete);73 }68 }</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":21,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I’m on page “<tabTitle>Jy 20820 es reindex stream model hydration by Vasi</tabTitle>” with “<selection>@@ -5,69 +5,64 @@5namespace Jiminny\\Component\\ES\\Processor\\Actions;5namespace Jiminny\\Component\\ES\\Processor\\Actions;667use Elastica\\Document;7use Elastica\\Document;8-use Illuminate\\Support\\Collection;9use Jiminny\\Component\\ElasticSearch\\Contract\\Searchable;8use Jiminny\\Component\\ElasticSearch\\Contract\\Searchable;10use Jiminny\\Component\\ES\\Processor\\DTOs\\DocumentLoad;9use Jiminny\\Component\\ES\\Processor\\DTOs\\DocumentLoad;11use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;10use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;12use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;11use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;13-use Jiminny\\Component\\ES\\Processor\\Traits\\SkipActivityTrait;14use Jiminny\\Exceptions\\SyncActivityException;12use Jiminny\\Exceptions\\SyncActivityException;15use Jiminny\\Models\\Model;13use Jiminny\\Models\\Model;16use Sentry\\Laravel\\Facade as Sentry;14use Sentry\\Laravel\\Facade as Sentry;15+use Throwable;171618class LoadDocumentsAction17class LoadDocumentsAction19{18{20-use SkipActivityTrait;19+public function __construct(21-20+private readonly EntityQueryBuilder $queryBuilder22-private const int RDS_CHUNK_SIZE = 250;21+ ) {22+ }232324-/**25- * @codeCoverageIgnore26- */27public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad24public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad28 {25 {29$documentsToUpdate = new SimpleCollection();26$documentsToUpdate = new SimpleCollection();30$documentsToDelete = new SimpleCollection();27$documentsToDelete = new SimpleCollection();312832-// do get mariadb data29+$query = $this->queryBuilder->getEntityQuery($updateTarget, $entityIdsList);33-$query = EntityQueryBuilder::getEntityQuery($updateTarget, $entityIdsList);343035-$query->chunkByIdDesc(31+/** @var Model&Searchable $entityModel */36-self::RDS_CHUNK_SIZE,32+foreach ($query->cursor() as $entityModel) {37-function (Collection $entityModels) use ($documentsToUpdate, $documentsToDelete) {33+if ($entityModel->isDeleted()) {38-/** @var Model&Searchable $entityForDeletion */34+/**39-foreach ($entityModels->whereNotNull('deleted_at') as $entityForDeletion) {35+ * Cleanup (from ElasticSearch) scheduled entities that were recently deleted.40-$documentsToDelete->add($entityForDeletion->getId());36+ * After a deletion, no more updates on a record are expected, so the operation is considered final,41- }37+ * unless the record is restored.42-38+ */43-/** @var Model&Searchable $entityModel */39+$documentsToDelete->add($entityModel->getId());44-foreach ($entityModels->whereNull('deleted_at') as $entityModel) {40+ } else {45-if (self::shouldSkipActivity($entityModel)) {41+try {46-/**42+$documentsToUpdate->add(47- * If the activity type is in the skip list, we should not push it for indexing.43+new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())48- * If an ES record already exists, we should remove it to free up storage and processing power44+ );49- */45+ } catch (Throwable $error) {50-$documentsToDelete->add($entityModel->getId());46+ Sentry::captureException(51-47+new SyncActivityException(52-continue;48+'ES entity async RDS build data failed',53- }49+$error->getCode(),54-50+$error55-try {51+ )56-$documentsToUpdate->add(52+ );57-new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())58- );59- } catch (\\Throwable $error) {60- Sentry::captureException(61-new SyncActivityException(62-'ES entity async RDS build data failed',63-$error->getCode(),64-$error65- )66- );67- }68 }53 }69 }54 }70- );55+56+/**57+ * Clean up fragmented memory.58+ * Dropping relations and unsetting the entity model after hydration and usage,59+ * allows GC to remove heap memory allocations, and recycle already allocated memory,60+ * instead of allocating more memory from OS.61+ * Unset operations signal GC to collect destroyed object memory62+ */63+$entityModel->setRelations([]);64+ unset($entityModel);65+ }716672return new DocumentLoad($documentsToUpdate, $documentsToDelete);67return new DocumentLoad($documentsToUpdate, $documentsToDelete);73 }68 }</selection>” selected.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Collapse","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Listen","depth":22,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":20,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Show thinking","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Gemini said","depth":20,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Overview","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Overview","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"This diff refactors the","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"LoadDocumentsAction","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"class to optimize memory usage and data processing. It transitions the database query execution from batch chunking to lazy loading using cursors, introduces explicit memory management techniques, and updates the class structure to use dependency injection.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Architectural & Structural Changes","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Architectural & Structural Changes","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Dependency Injection:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Injected","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"EntityQueryBuilder","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"via the constructor instead of calling it statically.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Removed Traits & Constants:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Removed the","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SkipActivityTrait","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entirely (and its associated skip logic), as well as the","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"RDS_CHUNK_SIZE","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"constant.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Namespace Imports:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Added the","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Throwable","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"import and removed","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Illuminate\\Support\\Collection","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Data Processing Refactor","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Data Processing Refactor","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Cursor Implementation:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Replaced","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"chunkByIdDesc","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"with","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"cursor()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", iterating through records sequentially rather than loading batches of 250 into memory.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Simplified Deletion Checks:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Replaced Laravel collection filtering (","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"whereNotNull('deleted_at')","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") with a direct","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$entityModel->isDeleted()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"check on each model during iteration.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Removed Skip Logic:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Removed the","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"shouldSkipActivity","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"check, meaning all non-deleted models are now directly processed for updates.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Exception Handling:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updated the catch block to use the imported","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Throwable","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"interface rather than the fully qualified","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\\Throwable","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Memory Optimization","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Memory Optimization","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Explicit Garbage Collection:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Added specific cleanup steps inside the iteration loop. Dropping loaded relationships (","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$entityModel->setRelations([])","depth":27,"bounds":{"left":0.32978722,"top":0.0,"width":0.08377659,"height":0.014764565},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") and unsetting the model (","depth":26,"bounds":{"left":0.3259641,"top":0.0,"width":0.10239362,"height":0.057861134},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"unset($entityModel)","depth":27,"bounds":{"left":0.32978722,"top":0.0035913808,"width":0.05319149,"height":0.014764565},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") explicitly signals the PHP Garbage Collector to free and recycle heap memory, preventing excessive OS memory allocation during large stream hydration.","depth":26,"bounds":{"left":0.3259641,"top":0.0023942539,"width":0.10239362,"height":0.09936153},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Good response","depth":22,"bounds":{"left":0.31000665,"top":0.12290503,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bad response","depth":22,"bounds":{"left":0.32064494,"top":0.12290503,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Share & export","depth":21,"bounds":{"left":0.33128324,"top":0.12290503,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy","depth":22,"bounds":{"left":0.34192154,"top":0.12290503,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":21,"bounds":{"left":0.35255983,"top":0.12290503,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":21,"bounds":{"left":0.3259641,"top":0.18355946,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Edit","depth":21,"bounds":{"left":0.34059176,"top":0.18355946,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said You are seasoned code reviewer and your task is to make detailed code review of summarized page. First understand the code changes, then evaluate it and try to find potential issues and bottlenecks.","depth":21,"bounds":{"left":0.36053857,"top":0.19313647,"width":0.051861703,"height":0.09577015},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"bounds":{"left":0.30302528,"top":0.19393456,"width":0.019946808,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You are seasoned code reviewer and your task is to make detailed code","depth":23,"bounds":{"left":0.36053857,"top":0.19473264,"width":0.047872342,"height":0.073822826},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"review of summarized page. First understand the code changes, then","depth":23,"bounds":{"left":0.36053857,"top":0.27134877,"width":0.04886968,"height":0.073822826},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"evaluate it and try to find potential issues and bottlenecks.","depth":23,"bounds":{"left":0.36053857,"top":0.2905028,"width":0.049700797,"height":0.054668795},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Expand","depth":21,"bounds":{"left":0.41240028,"top":0.19313647,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Listen","depth":21,"bounds":{"left":0.41771942,"top":0.32083002,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":20,"bounds":{"left":0.41771942,"top":0.31524342,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Show thinking","depth":25,"bounds":{"left":0.32662898,"top":0.32322428,"width":0.030917553,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Gemini said","depth":20,"bounds":{"left":0.32430187,"top":0.36472467,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":21,"bounds":{"left":0.32430187,"top":0.36671987,"width":0.04105718,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Code Review: LoadDocumentsAction Refactoring","depth":23,"bounds":{"left":0.31333113,"top":0.36552274,"width":0.11502659,"height":0.03830806},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Code Review:","depth":24,"bounds":{"left":0.31333113,"top":0.36711892,"width":0.036402926,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"LoadDocumentsAction","depth":25,"bounds":{"left":0.35172874,"top":0.36711892,"width":0.06067154,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Refactoring","depth":24,"bounds":{"left":0.31333113,"top":0.36711892,"width":0.10239362,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"As requested, I have reviewed the refactoring of the","depth":24,"bounds":{"left":0.31333113,"top":0.41260973,"width":0.11087101,"height":0.037110932},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"LoadDocumentsAction","depth":25,"bounds":{"left":0.33111703,"top":0.43455705,"width":0.053025264,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"class. While the intent to modernize the architecture and optimize memory is clear, there are several critical architectural flaws and potential bottlenecks in the new implementation that need to be addressed before this goes to production.","depth":24,"bounds":{"left":0.31333113,"top":0.43335995,"width":0.112865694,"height":0.14086193},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Here is my detailed evaluation.","depth":24,"bounds":{"left":0.31333113,"top":0.58739024,"width":0.07347074,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"1. Strengths & Positive Changes","depth":23,"bounds":{"left":0.31333113,"top":0.63766956,"width":0.11502659,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1. Strengths & Positive Changes","depth":24,"bounds":{"left":0.31333113,"top":0.6392658,"width":0.08178192,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Dependency Injection:","depth":26,"bounds":{"left":0.3259641,"top":0.66560256,"width":0.05851064,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Moving","depth":26,"bounds":{"left":0.38447472,"top":0.66560256,"width":0.020113032,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"EntityQueryBuilder","depth":27,"bounds":{"left":0.32795876,"top":0.6875499,"width":0.050199468,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"from a static call to an injected dependency significantly improves the testability of the class. You can now easily mock the query builder in your unit tests.","depth":26,"bounds":{"left":0.3259641,"top":0.6863527,"width":0.10239362,"height":0.09936153},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Simplified Readability:","depth":26,"bounds":{"left":0.3259641,"top":0.79888266,"width":0.058344416,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Replacing the nested closures required by","depth":26,"bounds":{"left":0.3259641,"top":0.79888266,"width":0.094082445,"height":0.037110932},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"chunkByIdDesc","depth":27,"bounds":{"left":0.32795876,"top":0.8415802,"width":0.036236703,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"with a flatter","depth":26,"bounds":{"left":0.36619017,"top":0.84038305,"width":0.03324468,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"foreach","depth":27,"bounds":{"left":0.40142953,"top":0.8415802,"width":0.019614361,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"structure makes the code easier to read and reason about.","depth":26,"bounds":{"left":0.3259641,"top":0.84038305,"width":0.09840426,"height":0.057861134},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Garbage Collection Awareness:","depth":26,"bounds":{"left":0.3259641,"top":0.9114126,"width":0.0809508,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The developer is actively thinking about heap memory and Garbage Collection (GC), which is crucial for background workers and hydration scripts.","depth":26,"bounds":{"left":0.3259641,"top":0.9114126,"width":0.10023271,"height":0.0885874},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"2. Critical Issues & Bottlenecks","depth":23,"bounds":{"left":0.31333113,"top":1.0,"width":0.11502659,"height":-0.048683167},"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2. Critical Issues & Bottlenecks","depth":24,"bounds":{"left":0.31333113,"top":1.0,"width":0.08045213,"height":-0.05027938},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"A. The \"Infinite Accumulation\" Memory Leak","depth":23,"bounds":{"left":0.31333113,"top":1.0,"width":0.11502659,"height":-0.090183616},"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"A. The \"Infinite Accumulation\" Memory Leak","depth":24,"bounds":{"left":0.31333113,"top":1.0,"width":0.11419548,"height":-0.09177971},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The primary goal of this refactor was memory optimization, but the implementation defeats its own purpose.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Issue:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The code iterates over the database cursor and manually unsets","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$entityModel","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to free memory. However, it simultaneously instantiates new","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Document","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"objects and adds them to","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$documentsToUpdate","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(and IDs to","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$documentsToDelete","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":").","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Bottleneck:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"These collections are not flushed or processed within the loop; they are accumulated and returned at the end of the method. If this script processes 500,000 records,","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$documentsToUpdate","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"will hold 500,000 ElasticSearch","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Document","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"objects in RAM at once, inevitably leading to an Out Of Memory (OOM) fatal error.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"B. Laravel cursor() and N+1 Query Problems","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"B. Laravel","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"cursor()","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and N+1 Query Problems","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Replacing","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"chunkByIdDesc()","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"with","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"cursor()","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"introduces a severe database performance risk.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Issue:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Laravel's","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"cursor()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"executes a single query and uses a PHP generator to yield results one by one via a PDO cursor. Because it does not process models in batches,","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"cursor()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"cannot eager-load relationships.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Bottleneck:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$entityModel->getIndexableAttributes()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"relies on","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"any","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"database relationships (e.g., getting a user's company or tags), it will trigger an N+1 query. For 100,000 records, this will execute 100,001 database queries, absolutely hammering the database.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"C. Long-Running PDO Connections","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"C. Long-Running PDO Connections","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Issue:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Because","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"cursor()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"keeps a single database connection open while iterating through the results, any network latency encountered inside the loop extends the transaction time.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Bottleneck:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If ElasticSearch","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Document","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"instantiation or the Sentry API calls (on failure) take time, the PDO connection to the MariaDB database will remain open for an extended period, potentially leading to connection timeouts, blocked processes, or database lock exhaustion.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"3. Minor Issues & Observations","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3. Minor Issues & Observations","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Missing Skip Logic:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The removal of","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SkipActivityTrait","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"assumes these models no longer need to be bypassed. If this was an accidental omission, you will end up polluting ElasticSearch with activity logs that were previously filtered out, wasting ES storage and processing power.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Synchronous Sentry Calls:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If a specific batch of data is malformed and throws multiple","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Throwable","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"errors consecutively,","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Sentry::captureException","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"will make synchronous outbound HTTP calls for every failed record. This will severely degrade the throughput of the hydration process.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"4. Recommendations for Refactoring","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"4. Recommendations for Refactoring","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"To resolve these issues, I recommend a hybrid approach utilizing Laravel's","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"lazyById()","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(or returning to chunking) combined with batch-processing the ElasticSearch payloads:","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Use","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"lazyById()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"instead of","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"cursor()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* Laravel's","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"lazyById(250)","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"fetches records in chunks under the hood (allowing for eager loading of relations without N+1) but yields them as a flat generator to the","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"foreach","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"loop. This gives you the clean syntax of a generator with the safety of chunked eager loading.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Dispatch to ElasticSearch Inside the Loop:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* Do not wait until the end of the method to return massive collections.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Keep a counter. When","depth":28,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$documentsToUpdate","depth":29,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"reaches a certain threshold (e.g., 500 documents), dispatch them to ElasticSearch, empty the","depth":28,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SimpleCollection","depth":29,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", and continue the loop.","depth":28,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Group Sentry Exceptions:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Consider implementing a circuit breaker or batching error logs so that a sudden spike in formatting errors doesn't result in thousands of synchronous API calls to Sentry.","depth":28,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Good response","depth":21,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bad response","depth":21,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Redo","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Share & export","depth":20,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":20,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXTextArea","text":"Enter a prompt for Gemini\nencrypted","depth":20,"bounds":{"left":0.31665558,"top":0.8216281,"width":0.10638298,"height":0.01915403},"on_screen":true,"value":"Enter a prompt for Gemini\nencrypted","help_text":"","role_description":"text entry area","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Enter a prompt for Gemini","depth":21,"bounds":{"left":0.32330453,"top":0.82202715,"width":0.069980055,"height":0.018355945},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"encrypted","depth":21,"bounds":{"left":0.31565824,"top":0.8216281,"width":0.0066489363,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Open upload file menu","depth":20,"bounds":{"left":0.31266624,"top":0.8575419,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Tools","depth":18,"bounds":{"left":0.32862368,"top":0.8575419,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open mode picker","depth":20,"bounds":{"left":0.3856383,"top":0.85514766,"width":0.026097074,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pro","depth":23,"bounds":{"left":0.39095744,"top":0.8639266,"width":0.007480053,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Microphone","depth":19,"bounds":{"left":0.41373006,"top":0.85514766,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send message","depth":19,"bounds":{"left":0.42004654,"top":0.85434955,"width":0.013962766,"height":0.033519555},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Your Jiminny chats aren’t used to improve our models. Gemini is AI. It can make mistakes, so double check it.","depth":17,"bounds":{"left":0.30884308,"top":0.90901834,"width":0.11951463,"height":0.025139665},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Your privacy & Gemini Opens in a new window","depth":17,"bounds":{"left":0.39079124,"top":0.92178774,"width":0.040059842,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Your privacy & Gemini","depth":18,"bounds":{"left":0.39079124,"top":0.92178774,"width":0.040059842,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Opens in a new window","depth":19,"bounds":{"left":0.30302528,"top":0.92098963,"width":0.043218084,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Summarize page","depth":7,"bounds":{"left":0.30867687,"top":0.95730245,"width":0.053523935,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Summarize page","depth":9,"bounds":{"left":0.31432846,"top":0.96249,"width":0.042220745,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Skip to content","depth":7,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip to content","depth":8,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Open menu","depth":11,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Homepage (g then d)","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"jiminny","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"jiminny","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"app","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"app","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Search or jump to…","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Type","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to search","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Chat with Copilot","depth":11,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Open Copilot…","depth":10,"on_screen":false,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXMenuButton","text":"Create new...","depth":10,"on_screen":false,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"All issues(g then i)","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"All pull requests","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"All repositories","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"You have unread notifications(g then n)","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open user navigation menu","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Repository navigation","depth":10,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Repository navigation","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Code","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Code","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Pull requests (33)","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"33","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Agents","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Agents","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Actions","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Actions","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Wiki","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Wiki","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Security and quality (2)","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Security and quality","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Insights","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Insights","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Settings","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Settings","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Important update","depth":11,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Important update","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"On April 24 we'll start using GitHub Copilot interaction data for AI model training unless you opt out.","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review this update","depth":11,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review this update","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and manage your preferences in your","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"GitHub account settings","depth":11,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"GitHub account settings","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Dismiss banner","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Jy 20820 es reindex stream model hydration #12059 Edit title","depth":13,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Jy 20820 es reindex stream model hydration","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"12059","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Edit title","depth":14,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Preview","depth":13,"on_screen":false,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Preview","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Awaiting approval","depth":13,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Awaiting approval","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Code","depth":13,"on_screen":false,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Code","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Open","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Vasil-Jiminny","depth":15,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Vasil-Jiminny","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"wants to merge 35 commits into","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"master","depth":15,"on_screen":false,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"master","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"from","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20820-es-reindex-stream-model-hydration","depth":16,"on_screen":false,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20820-es-reindex-stream-model-hydration","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy head branch name to clipboard","depth":16,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Lines changed: 363 additions & 140 deletions","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Conversation (8)","depth":16,"on_screen":false,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Conversation","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"8","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Commits (35)","depth":16,"on_screen":false,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Commits","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"35","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Checks (3)","depth":16,"on_screen":false,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Checks","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-4376177274890958263
|
-354298913592723067
|
click
|
accessibility
|
NULL
|
Platform Sprint 3 Q2 - Platform Team - Scrum Board Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Unnamed Group
SevenShores\Hubspot\Exceptions\BadRequest: Client error: `POST [URL_WITH_CREDENTIALS] -5,69 +5,64 @@5namespace Jiminny\Component\ES\Processor\Actions;5namespace Jiminny\Component\ES\Processor\Actions;667use Elastica\Document;7use Elastica\Document;8-use Illuminate\Support\Collection;9use Jiminny\Component\ElasticSearch\Contract\Searchable;8use Jiminny\Component\ElasticSearch\Contract\Searchable;10use Jiminny\Component\ES\Processor\DTOs\DocumentLoad;9use Jiminny\Component\ES\Processor\DTOs\DocumentLoad;11use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;10use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;12use Jiminny\Component\ES\Processor\EntityQueryBuilder;11use Jiminny\Component\ES\Processor\EntityQueryBuilder;13-use Jiminny\Component\ES\Processor\Traits\SkipActivityTrait;14use Jiminny\Exceptions\SyncActivityException;12use Jiminny\Exceptions\SyncActivityException;15use Jiminny\Models\Model;13use Jiminny\Models\Model;16use Sentry\Laravel\Facade as Sentry;14use Sentry\Laravel\Facade as Sentry;15+use Throwable;171618class LoadDocumentsAction17class LoadDocumentsAction19{18{20-use SkipActivityTrait;19+public function __construct(21-20+private readonly EntityQueryBuilder $queryBuilder22-private const int RDS_CHUNK_SIZE = 250;21+ ) {22+ }232324-/**25- * @codeCoverageIgnore26- */27public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad24public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad28 {25 {29$documentsToUpdate = new SimpleCollection();26$documentsToUpdate = new SimpleCollection();30$documentsToDelete = new SimpleCollection();27$documentsToDelete = new SimpleCollection();312832-// do get mariadb data29+$query = $this->queryBuilder->getEntityQuery($updateTarget, $entityIdsList);33-$query = EntityQueryBuilder::getEntityQuery($updateTarget, $entityIdsList);343035-$query->chunkByIdDesc(31+/** @var Model&Searchable $entityModel */36-self::RDS_CHUNK_SIZE,32+foreach ($query->cursor() as $entityModel) {37-function (Collection $entityModels) use ($documentsToUpdate, $documentsToDelete) {33+if ($entityModel->isDeleted()) {38-/** @var Model&Searchable $entityForDeletion */34+/**39-foreach ($entityModels->whereNotNull('deleted_at') as $entityForDeletion) {35+ * Cleanup (from ElasticSearch) scheduled entities that were recently deleted.40-$documentsToDelete->add($entityForDeletion->getId());36+ * After a deletion, no more updates on a record are expected, so the operation is considered final,41- }37+ * unless the record is restored.42-38+ */43-/** @var Model&Searchable $entityModel */39+$documentsToDelete->add($entityModel->getId());44-foreach ($entityModels->whereNull('deleted_at') as $entityModel) {40+ } else {45-if (self::shouldSkipActivity($entityModel)) {41+try {46-/**42+$documentsToUpdate->add(47- * If the activity type is in the skip list, we should not push it for indexing.43+new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())48- * If an ES record already exists, we should remove it to free up storage and processing power44+ );49- */45+ } catch (Throwable $error) {50-$documentsToDelete->add($entityModel->getId());46+ Sentry::captureException(51-47+new SyncActivityException(52-continue;48+'ES entity async RDS build data failed',53- }49+$error->getCode(),54-50+$error55-try {51+ )56-$documentsToUpdate->add(52+ );57-new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())58- );59- } catch (\Throwable $error) {60- Sentry::captureException(61-new SyncActivityException(62-'ES entity async RDS build data failed',63-$error->getCode(),64-$error65- )66- );67- }68 }53 }69 }54 }70- );55+56+/**57+ * Clean up fragmented memory.58+ * Dropping relations and unsetting the entity model after hydration and usage,59+ * allows GC to remove heap memory allocations, and recycle already allocated memory,60+ * instead of allocating more memory from OS.61+ * Unset operations signal GC to collect destroyed object memory62+ */63+$entityModel->setRelations([]);64+ unset($entityModel);65+ }716672return new DocumentLoad($documentsToUpdate, $documentsToDelete);67return new DocumentLoad($documentsToUpdate, $documentsToDelete);73 }68 }</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>Jy 20820 es reindex stream model hydration by Vasi</tabTitle>” with “<selection>@@ -5,69 +5,64 @@5namespace Jiminny\Component\ES\Processor\Actions;5namespace Jiminny\Component\ES\Processor\Actions;667use Elastica\Document;7use Elastica\Document;8-use Illuminate\Support\Collection;9use Jiminny\Component\ElasticSearch\Contract\Searchable;8use Jiminny\Component\ElasticSearch\Contract\Searchable;10use Jiminny\Component\ES\Processor\DTOs\DocumentLoad;9use Jiminny\Component\ES\Processor\DTOs\DocumentLoad;11use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;10use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;12use Jiminny\Component\ES\Processor\EntityQueryBuilder;11use Jiminny\Component\ES\Processor\EntityQueryBuilder;13-use Jiminny\Component\ES\Processor\Traits\SkipActivityTrait;14use Jiminny\Exceptions\SyncActivityException;12use Jiminny\Exceptions\SyncActivityException;15use Jiminny\Models\Model;13use Jiminny\Models\Model;16use Sentry\Laravel\Facade as Sentry;14use Sentry\Laravel\Facade as Sentry;15+use Throwable;171618class LoadDocumentsAction17class LoadDocumentsAction19{18{20-use SkipActivityTrait;19+public function __construct(21-20+private readonly EntityQueryBuilder $queryBuilder22-private const int RDS_CHUNK_SIZE = 250;21+ ) {22+ }232324-/**25- * @codeCoverageIgnore26- */27public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad24public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad28 {25 {29$documentsToUpdate = new SimpleCollection();26$documentsToUpdate = new SimpleCollection();30$documentsToDelete = new SimpleCollection();27$documentsToDelete = new SimpleCollection();312832-// do get mariadb data29+$query = $this->queryBuilder->getEntityQuery($updateTarget, $entityIdsList);33-$query = EntityQueryBuilder::getEntityQuery($updateTarget, $entityIdsList);343035-$query->chunkByIdDesc(31+/** @var Model&Searchable $entityModel */36-self::RDS_CHUNK_SIZE,32+foreach ($query->cursor() as $entityModel) {37-function (Collection $entityModels) use ($documentsToUpdate, $documentsToDelete) {33+if ($entityModel->isDeleted()) {38-/** @var Model&Searchable $entityForDeletion */34+/**39-foreach ($entityModels->whereNotNull('deleted_at') as $entityForDeletion) {35+ * Cleanup (from ElasticSearch) scheduled entities that were recently deleted.40-$documentsToDelete->add($entityForDeletion->getId());36+ * After a deletion, no more updates on a record are expected, so the operation is considered final,41- }37+ * unless the record is restored.42-38+ */43-/** @var Model&Searchable $entityModel */39+$documentsToDelete->add($entityModel->getId());44-foreach ($entityModels->whereNull('deleted_at') as $entityModel) {40+ } else {45-if (self::shouldSkipActivity($entityModel)) {41+try {46-/**42+$documentsToUpdate->add(47- * If the activity type is in the skip list, we should not push it for indexing.43+new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())48- * If an ES record already exists, we should remove it to free up storage and processing power44+ );49- */45+ } catch (Throwable $error) {50-$documentsToDelete->add($entityModel->getId());46+ Sentry::captureException(51-47+new SyncActivityException(52-continue;48+'ES entity async RDS build data failed',53- }49+$error->getCode(),54-50+$error55-try {51+ )56-$documentsToUpdate->add(52+ );57-new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())58- );59- } catch (\Throwable $error) {60- Sentry::captureException(61-new SyncActivityException(62-'ES entity async RDS build data failed',63-$error->getCode(),64-$error65- )66- );67- }68 }53 }69 }54 }70- );55+56+/**57+ * Clean up fragmented memory.58+ * Dropping relations and unsetting the entity model after hydration and usage,59+ * allows GC to remove heap memory allocations, and recycle already allocated memory,60+ * instead of allocating more memory from OS.61+ * Unset operations signal GC to collect destroyed object memory62+ */63+$entityModel->setRelations([]);64+ unset($entityModel);65+ }716672return new DocumentLoad($documentsToUpdate, $documentsToDelete);67return new DocumentLoad($documentsToUpdate, $documentsToDelete);73 }68 }</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Collapse
Listen
Show more options
Show thinking
Gemini said
Gemini said
Overview
Overview
This diff refactors the
LoadDocumentsAction
class to optimize memory usage and data processing. It transitions the database query execution from batch chunking to lazy loading using cursors, introduces explicit memory management techniques, and updates the class structure to use dependency injection.
Architectural & Structural Changes
Architectural & Structural Changes
Dependency Injection:
Injected
EntityQueryBuilder
via the constructor instead of calling it statically.
Removed Traits & Constants:
Removed the
SkipActivityTrait
entirely (and its associated skip logic), as well as the
RDS_CHUNK_SIZE
constant.
Namespace Imports:
Added the
Throwable
import and removed
Illuminate\Support\Collection
.
Data Processing Refactor
Data Processing Refactor
Cursor Implementation:
Replaced
chunkByIdDesc
with
cursor()
, iterating through records sequentially rather than loading batches of 250 into memory.
Simplified Deletion Checks:
Replaced Laravel collection filtering (
whereNotNull('deleted_at')
) with a direct
$entityModel->isDeleted()
check on each model during iteration.
Removed Skip Logic:
Removed the
shouldSkipActivity
check, meaning all non-deleted models are now directly processed for updates.
Exception Handling:
Updated the catch block to use the imported
Throwable
interface rather than the fully qualified
\Throwable
.
Memory Optimization
Memory Optimization
Explicit Garbage Collection:
Added specific cleanup steps inside the iteration loop. Dropping loaded relationships (
$entityModel->setRelations([])
) and unsetting the model (
unset($entityModel)
) explicitly signals the PHP Garbage Collector to free and recycle heap memory, preventing excessive OS memory allocation during large stream hydration.
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said You are seasoned code reviewer and your task is to make detailed code review of summarized page. First understand the code changes, then evaluate it and try to find potential issues and bottlenecks.
You said
You are seasoned code reviewer and your task is to make detailed code
review of summarized page. First understand the code changes, then
evaluate it and try to find potential issues and bottlenecks.
Expand
Listen
Show more options
Show thinking
Gemini said
Gemini said
Code Review: LoadDocumentsAction Refactoring
Code Review:
LoadDocumentsAction
Refactoring
As requested, I have reviewed the refactoring of the
LoadDocumentsAction
class. While the intent to modernize the architecture and optimize memory is clear, there are several critical architectural flaws and potential bottlenecks in the new implementation that need to be addressed before this goes to production.
Here is my detailed evaluation.
1. Strengths & Positive Changes
1. Strengths & Positive Changes
Dependency Injection:
Moving
EntityQueryBuilder
from a static call to an injected dependency significantly improves the testability of the class. You can now easily mock the query builder in your unit tests.
Simplified Readability:
Replacing the nested closures required by
chunkByIdDesc
with a flatter
foreach
structure makes the code easier to read and reason about.
Garbage Collection Awareness:
The developer is actively thinking about heap memory and Garbage Collection (GC), which is crucial for background workers and hydration scripts.
2. Critical Issues & Bottlenecks
2. Critical Issues & Bottlenecks
A. The "Infinite Accumulation" Memory Leak
A. The "Infinite Accumulation" Memory Leak
The primary goal of this refactor was memory optimization, but the implementation defeats its own purpose.
The Issue:
The code iterates over the database cursor and manually unsets
$entityModel
to free memory. However, it simultaneously instantiates new
Document
objects and adds them to
$documentsToUpdate
(and IDs to
$documentsToDelete
).
The Bottleneck:
These collections are not flushed or processed within the loop; they are accumulated and returned at the end of the method. If this script processes 500,000 records,
$documentsToUpdate
will hold 500,000 ElasticSearch
Document
objects in RAM at once, inevitably leading to an Out Of Memory (OOM) fatal error.
B. Laravel cursor() and N+1 Query Problems
B. Laravel
cursor()
and N+1 Query Problems
Replacing
chunkByIdDesc()
with
cursor()
introduces a severe database performance risk.
The Issue:
Laravel's
cursor()
executes a single query and uses a PHP generator to yield results one by one via a PDO cursor. Because it does not process models in batches,
cursor()
cannot eager-load relationships.
*
The Bottleneck:
If
$entityModel->getIndexableAttributes()
relies on
any
database relationships (e.g., getting a user's company or tags), it will trigger an N+1 query. For 100,000 records, this will execute 100,001 database queries, absolutely hammering the database.
C. Long-Running PDO Connections
C. Long-Running PDO Connections
The Issue:
Because
cursor()
keeps a single database connection open while iterating through the results, any network latency encountered inside the loop extends the transaction time.
The Bottleneck:
If ElasticSearch
Document
instantiation or the Sentry API calls (on failure) take time, the PDO connection to the MariaDB database will remain open for an extended period, potentially leading to connection timeouts, blocked processes, or database lock exhaustion.
3. Minor Issues & Observations
3. Minor Issues & Observations
Missing Skip Logic:
The removal of
SkipActivityTrait
assumes these models no longer need to be bypassed. If this was an accidental omission, you will end up polluting ElasticSearch with activity logs that were previously filtered out, wasting ES storage and processing power.
Synchronous Sentry Calls:
If a specific batch of data is malformed and throws multiple
Throwable
errors consecutively,
Sentry::captureException
will make synchronous outbound HTTP calls for every failed record. This will severely degrade the throughput of the hydration process.
4. Recommendations for Refactoring
4. Recommendations for Refactoring
To resolve these issues, I recommend a hybrid approach utilizing Laravel's
lazyById()
(or returning to chunking) combined with batch-processing the ElasticSearch payloads:
Use
lazyById()
instead of
cursor()
:
* Laravel's
lazyById(250)
fetches records in chunks under the hood (allowing for eager loading of relations without N+1) but yields them as a flat generator to the
foreach
loop. This gives you the clean syntax of a generator with the safety of chunked eager loading.
Dispatch to ElasticSearch Inside the Loop:
* Do not wait until the end of the method to return massive collections.
Keep a counter. When
$documentsToUpdate
reaches a certain threshold (e.g., 500 documents), dispatch them to ElasticSearch, empty the
SimpleCollection
, and continue the loop.
Group Sentry Exceptions:
Consider implementing a circuit breaker or batching error logs so that a sudden spike in formatting errors doesn't result in thousands of synchronous API calls to Sentry.
Good response
Bad response
Redo
Share & export
Copy
Show more options
Enter a prompt for Gemini
encrypted
Enter a prompt for Gemini
encrypted
Open upload file menu
Tools
Open mode picker
Pro
Microphone
Send message
Your Jiminny chats aren’t used to improve our models. Gemini is AI. It can make mistakes, so double check it.
Your privacy & Gemini Opens in a new window
Your privacy & Gemini
Opens in a new window
Summarize page
Summarize page
Skip to content
Skip to content
Open menu
Homepage (g then d)
jiminny
jiminny
app
app
Search or jump to…
Type
/
to search
Chat with Copilot
Open Copilot…
Create new...
All issues(g then i)
All pull requests
All repositories
You have unread notifications(g then n)
Open user navigation menu
Repository navigation
Repository navigation
Code
Code
Pull requests (33)
Pull requests
(
33
)
Agents
Agents
Actions
Actions
Wiki
Wiki
Security and quality (2)
Security and quality
(
2
)
Insights
Insights
Settings
Settings
Important update
Important update
On April 24 we'll start using GitHub Copilot interaction data for AI model training unless you opt out.
Review this update
Review this update
and manage your preferences in your
GitHub account settings
GitHub account settings
.
Dismiss banner
Jy 20820 es reindex stream model hydration #12059 Edit title
Jy 20820 es reindex stream model hydration
#
12059
Edit title
Preview
Preview
Awaiting approval
Awaiting approval
Code
Code
Open
Vasil-Jiminny
Vasil-Jiminny
wants to merge 35 commits into
master
master
from
JY-20820-es-reindex-stream-model-hydration
JY-20820-es-reindex-stream-model-hydration
Copy head branch name to clipboard
Lines changed: 363 additions & 140 deletions
Conversation (8)
Conversation
(
8
)
Commits (35)
Commits
(
35
)
Checks (3)
Checks
(
3...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
9699
|
436
|
43
|
2026-05-08T13:17:04.540555+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778246224540_m2.jpg...
|
Firefox
|
Pull requests · screenpipe/screenpipe · GitHub — P Pull requests · screenpipe/screenpipe · GitHub — Personal...
|
True
|
github.com/screenpipe/screenpipe/pulls?page=2& github.com/screenpipe/screenpipe/pulls?page=2&q=is%3Apr+is%3Aclosed...
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Pull requests · screenpipe/screenpipe · GitHub
Pul Pull requests · screenpipe/screenpipe · GitHub
Pull requests · screenpipe/screenpipe · GitHub
Close tab
Home | Hostinger
Home | Hostinger
Login – Nginx Proxy Manager
Login – Nginx Proxy Manager
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Skip to content
Skip to content
Navigation Menu
Navigation Menu
Homepage
Platform
Solutions
Resources
Open Source
Enterprise
Pricing
Pricing
Search or jump to…
Search or jump to...
Sign in
Sign in
Sign up
Sign up
Appearance settings
screenpipe
screenpipe
/
screenpipe
screenpipe
Public
You must be signed in to change notification settings
Notifications
Fork 1.7k
Fork
1.7k
You must be signed in to star a repository
Star
18.6k
Code
Code
Issues 16
Issues
16
Pull requests 17
Pull requests
17
Discussions
Discussions
Actions
Actions
Projects
Projects
Security and quality
Security and quality
Insights
Insights
Pull requests: screenpipe/screenpipe
Pull requests: screenpipe/screenpipe
is:pr is:closed
Labels 43
Labels
43
Milestones 0
Milestones
0
New pull request
New pull request
Clear current search query, filters, and sorts
Clear current search query, filters, and sorts
17 Open
17 Open
1,593 Closed
1,593 Closed
Author
Author
Label
Label
Projects
Projects
Milestones
Milestones
Reviews
Reviews
Assignee
Assignee
Sort
Sort
Pull requests list
Pull requests list
docs(testing): add 3 recent regression test entries
docs(testing): add 3 recent regression test entries
#3224 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
testing: update spec from recent changes (2026-05-04)
testing: update spec from recent changes (2026-05-04)
#3223 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
fix: add circuit breaker for corrupted segmentation model
fix: add circuit breaker for corrupted segmentation model
#3222 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
2 comments
2
docs(testing): add a11y multi-line bbox regression entry
docs(testing): add a11y multi-line bbox regression entry
#3221 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
fix: add diagnostic logging for audio device configuration selection
fix: add diagnostic logging for audio device configuration selection
#3220 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
docs: improve SEO titles across generic pages
docs: improve SEO titles across generic pages
#3219 by
mintlify
mintlify
Bot
was merged
4 days ago
•
Review required before merging
Review required
1 comment
1
changelog: week of may 3, 2026
changelog: week of may 3, 2026
#3218 by
mintlify
mintlify
Bot
was closed
3 days ago
•
Review required before merging
Review required
2 comments
2
docs(testing): add multi-line text bbox capture regression test
docs(testing): add multi-line text bbox capture regression test
#3217 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
docs(testing): add Windows GetWindowRect bounds regression test
docs(testing): add Windows GetWindowRect bounds regression test
#3216 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
Fix devcontainer cargo path
Fix devcontainer cargo path
#3214 by
julpel8
julpel8
Contributor
was merged
4 days ago
•
Review required before merging
Review required
fix(settings): api key regenerate cancel, apply button, manual edit
fix(settings): api key regenerate cancel, apply button, manual edit
#3212 by
Anshgrover23
Anshgrover23...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Pull requests · screenpipe/screenpipe · GitHub","depth":4,"bounds":{"left":0.26097074,"top":0.0518755,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Pull requests · screenpipe/screenpipe · GitHub","depth":5,"bounds":{"left":0.27426863,"top":0.06304868,"width":0.080784574,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.36236703,"top":0.05905826,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Home | Hostinger","depth":4,"bounds":{"left":0.26097074,"top":0.08459697,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Home | Hostinger","depth":5,"bounds":{"left":0.27426863,"top":0.09577015,"width":0.03025266,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Login – Nginx Proxy Manager","depth":4,"bounds":{"left":0.26097074,"top":0.11731844,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Login – Nginx Proxy Manager","depth":5,"bounds":{"left":0.27426863,"top":0.12849163,"width":0.05069814,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Screenpipe — Archive","depth":4,"bounds":{"left":0.26097074,"top":0.15003991,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Screenpipe — Archive","depth":5,"bounds":{"left":0.27426863,"top":0.16121309,"width":0.037898935,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: archive.db","depth":4,"bounds":{"left":0.26097074,"top":0.18276137,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: archive.db","depth":5,"bounds":{"left":0.27426863,"top":0.19393456,"width":0.040724736,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: db.sqlite","depth":4,"bounds":{"left":0.26097074,"top":0.21548285,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: db.sqlite","depth":5,"bounds":{"left":0.27426863,"top":0.22665602,"width":0.03756649,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub","depth":4,"bounds":{"left":0.26097074,"top":0.2482043,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub","depth":5,"bounds":{"left":0.27426863,"top":0.25937748,"width":0.11469415,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"DXP4800PLUS-B5F8","depth":4,"bounds":{"left":0.26097074,"top":0.28092578,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"DXP4800PLUS-B5F8","depth":5,"bounds":{"left":0.27426863,"top":0.29209897,"width":0.036901597,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Оптичен интернет за дома - EON телевизия | Vivacom | 5G","depth":4,"bounds":{"left":0.26097074,"top":0.31364724,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Оптичен интернет за дома - EON телевизия | Vivacom | 5G","depth":5,"bounds":{"left":0.27426863,"top":0.32482043,"width":0.105884306,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.26379654,"top":0.34796488,"width":0.108211435,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.26379654,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"bounds":{"left":0.27476728,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.28590426,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.29704124,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bitwarden","depth":6,"bounds":{"left":0.3081782,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Skip to content","depth":6,"bounds":{"left":0.37466756,"top":0.0518755,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip to content","depth":7,"bounds":{"left":0.37466756,"top":0.05347167,"width":0.0029920214,"height":0.21468475},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Navigation Menu","depth":7,"bounds":{"left":0.37466756,"top":0.06464485,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Navigation Menu","depth":8,"bounds":{"left":0.37466756,"top":0.06743815,"width":0.038896278,"height":0.0518755},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Homepage","depth":7,"bounds":{"left":0.38530585,"top":0.06703911,"width":0.010638298,"height":0.027533919},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Platform","depth":12,"bounds":{"left":0.4012633,"top":0.06464485,"width":0.032413565,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Solutions","depth":12,"bounds":{"left":0.43367687,"top":0.06464485,"width":0.034242023,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Resources","depth":12,"bounds":{"left":0.46791887,"top":0.06464485,"width":0.03723404,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open Source","depth":12,"bounds":{"left":0.50515294,"top":0.06464485,"width":0.043550532,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Enterprise","depth":12,"bounds":{"left":0.54870343,"top":0.06464485,"width":0.03656915,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Pricing","depth":12,"bounds":{"left":0.5852726,"top":0.06464485,"width":0.021941489,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pricing","depth":14,"bounds":{"left":0.58793217,"top":0.07302474,"width":0.01662234,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Search or jump to…","depth":9,"bounds":{"left":0.8133311,"top":0.06863528,"width":0.10571808,"height":0.023942538},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Search or jump to...","depth":11,"bounds":{"left":0.8239694,"top":0.07462091,"width":0.042054523,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Sign in","depth":8,"bounds":{"left":0.923371,"top":0.06783719,"width":0.02244016,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sign in","depth":9,"bounds":{"left":0.92736036,"top":0.073822826,"width":0.014461436,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Sign up","depth":7,"bounds":{"left":0.94980055,"top":0.06783719,"width":0.024933511,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sign up","depth":8,"bounds":{"left":0.95412236,"top":0.073822826,"width":0.016289894,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Appearance settings","depth":9,"bounds":{"left":0.9787234,"top":0.06783719,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"screenpipe","depth":9,"bounds":{"left":0.3932846,"top":0.1245012,"width":0.032247342,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"screenpipe","depth":10,"bounds":{"left":0.3932846,"top":0.1245012,"width":0.032247342,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":9,"bounds":{"left":0.4268617,"top":0.1245012,"width":0.0018284575,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"screenpipe","depth":9,"bounds":{"left":0.43001994,"top":0.1245012,"width":0.033909574,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"screenpipe","depth":10,"bounds":{"left":0.43001994,"top":0.1245012,"width":0.033909574,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":9,"bounds":{"left":0.46891624,"top":0.12809257,"width":0.011968086,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"You must be signed in to change notification settings","depth":11,"bounds":{"left":0.8615359,"top":0.12210695,"width":0.04105718,"height":0.022346368},"on_screen":true,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Notifications","depth":12,"bounds":{"left":0.87383646,"top":0.1272945,"width":0.02443484,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Fork 1.7k","depth":11,"bounds":{"left":0.90525264,"top":0.12210695,"width":0.0390625,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Fork","depth":12,"bounds":{"left":0.9175532,"top":0.1272945,"width":0.009640957,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1.7k","depth":13,"bounds":{"left":0.93018615,"top":0.1272945,"width":0.007480053,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"You must be signed in to star a repository","depth":11,"bounds":{"left":0.94697475,"top":0.12210695,"width":0.042386968,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Star","depth":12,"bounds":{"left":0.95927525,"top":0.1272945,"width":0.010139627,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"18.6k","depth":13,"bounds":{"left":0.9724069,"top":0.1272945,"width":0.010305851,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Code","depth":11,"bounds":{"left":0.38530585,"top":0.1660016,"width":0.025099734,"height":0.023942538},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Code","depth":13,"bounds":{"left":0.3961104,"top":0.17118914,"width":0.011469414,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Issues 16","depth":11,"bounds":{"left":0.41306517,"top":0.1660016,"width":0.03956117,"height":0.023942538},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Issues","depth":13,"bounds":{"left":0.4240359,"top":0.17118914,"width":0.013630319,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"16","depth":13,"bounds":{"left":0.4429854,"top":0.17198724,"width":0.004654255,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Pull requests 17","depth":11,"bounds":{"left":0.4552859,"top":0.1660016,"width":0.054022606,"height":0.023942538},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests","depth":13,"bounds":{"left":0.4659242,"top":0.17118914,"width":0.02925532,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"17","depth":13,"bounds":{"left":0.50016624,"top":0.17198724,"width":0.004155585,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Discussions","depth":11,"bounds":{"left":0.5119681,"top":0.1660016,"width":0.040226065,"height":0.023942538},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Discussions","depth":13,"bounds":{"left":0.52327126,"top":0.17118914,"width":0.025598405,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Actions","depth":11,"bounds":{"left":0.55485374,"top":0.1660016,"width":0.03025266,"height":0.023942538},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Actions","depth":13,"bounds":{"left":0.5659907,"top":0.17118914,"width":0.015957447,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Projects","depth":11,"bounds":{"left":0.58776593,"top":0.1660016,"width":0.03174867,"height":0.023942538},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Projects","depth":13,"bounds":{"left":0.59890294,"top":0.17118914,"width":0.01761968,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Security and quality","depth":11,"bounds":{"left":0.6221742,"top":0.1660016,"width":0.05817819,"height":0.023942538},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Security and quality","depth":13,"bounds":{"left":0.63397604,"top":0.17118914,"width":0.04255319,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Insights","depth":11,"bounds":{"left":0.68301195,"top":0.1660016,"width":0.03125,"height":0.023942538},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Insights","depth":13,"bounds":{"left":0.69431514,"top":0.17118914,"width":0.016788565,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Pull requests: screenpipe/screenpipe","depth":10,"bounds":{"left":0.48520613,"top":0.21628092,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Pull requests: screenpipe/screenpipe","depth":11,"bounds":{"left":0.48520613,"top":0.22027135,"width":0.05701463,"height":0.1452514},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXTextField","text":"is:pr is:closed","depth":12,"bounds":{"left":0.48520613,"top":0.21628092,"width":0.25731382,"height":0.025538707},"on_screen":true,"value":"is:pr is:closed","help_text":"","role_description":"text field","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Labels 43","depth":12,"bounds":{"left":0.7478391,"top":0.21628092,"width":0.04338431,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Labels","depth":13,"bounds":{"left":0.75880986,"top":0.22226655,"width":0.016954787,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"43","depth":14,"bounds":{"left":0.7780917,"top":0.22386272,"width":0.0051529254,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Milestones 0","depth":12,"bounds":{"left":0.79089093,"top":0.21628092,"width":0.050199468,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Milestones","depth":13,"bounds":{"left":0.8018617,"top":0.22226655,"width":0.02642952,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":14,"bounds":{"left":0.8306183,"top":0.22386272,"width":0.002493351,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"New pull request","depth":10,"bounds":{"left":0.84375,"top":0.21628092,"width":0.045711435,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New pull request","depth":13,"bounds":{"left":0.8480718,"top":0.22226655,"width":0.03706782,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Clear current search query, filters, and sorts","depth":11,"bounds":{"left":0.48520613,"top":0.25618514,"width":0.10804521,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Clear current search query, filters, and sorts","depth":12,"bounds":{"left":0.49251994,"top":0.25618514,"width":0.10073138,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"17 Open","depth":12,"bounds":{"left":0.49085772,"top":0.29768556,"width":0.025598405,"height":0.016759777},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"17 Open","depth":13,"bounds":{"left":0.49750665,"top":0.29928172,"width":0.018949468,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1,593 Closed","depth":12,"bounds":{"left":0.52111036,"top":0.29768556,"width":0.03706782,"height":0.016759777},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1,593 Closed","depth":13,"bounds":{"left":0.5277593,"top":0.29928172,"width":0.030418882,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Author","depth":12,"bounds":{"left":0.67669547,"top":0.29768556,"width":0.018450798,"height":0.016759777},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Author","depth":13,"bounds":{"left":0.67669547,"top":0.29928172,"width":0.015791224,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Label","depth":12,"bounds":{"left":0.70578456,"top":0.29768556,"width":0.015458777,"height":0.016759777},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Label","depth":13,"bounds":{"left":0.70578456,"top":0.29928172,"width":0.012799202,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Projects","depth":13,"bounds":{"left":0.7318817,"top":0.29768556,"width":0.021609042,"height":0.016759777},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Projects","depth":14,"bounds":{"left":0.7318817,"top":0.29928172,"width":0.018949468,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Milestones","depth":13,"bounds":{"left":0.76545876,"top":0.29768556,"width":0.027094414,"height":0.016759777},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Milestones","depth":14,"bounds":{"left":0.76545876,"top":0.29928172,"width":0.02443484,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Reviews","depth":13,"bounds":{"left":0.80452126,"top":0.29768556,"width":0.02144282,"height":0.016759777},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Reviews","depth":14,"bounds":{"left":0.80452126,"top":0.29928172,"width":0.018783245,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Assignee","depth":12,"bounds":{"left":0.8366024,"top":0.29768556,"width":0.023603724,"height":0.016759777},"on_screen":true,"help_text":"Assignees","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Assignee","depth":13,"bounds":{"left":0.8366024,"top":0.29928172,"width":0.020944148,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Sort","depth":12,"bounds":{"left":0.8708444,"top":0.29768556,"width":0.012965426,"height":0.016759777},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Sort","depth":13,"bounds":{"left":0.8708444,"top":0.29928172,"width":0.008976064,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Pull requests list","depth":10,"bounds":{"left":0.48553857,"top":0.32801276,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Pull requests list","depth":11,"bounds":{"left":0.48553857,"top":0.33080608,"width":0.03174867,"height":0.08060654},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"docs(testing): add 3 recent regression test entries","depth":13,"bounds":{"left":0.49883643,"top":0.33758977,"width":0.12732713,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"docs(testing): add 3 recent regression test entries","depth":14,"bounds":{"left":0.49883643,"top":0.33758977,"width":0.12732713,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3224 by","depth":14,"bounds":{"left":0.49883643,"top":0.35993615,"width":0.019115692,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"bounds":{"left":0.51795214,"top":0.35993615,"width":0.023105053,"height":0.011971269},"on_screen":true,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"bounds":{"left":0.51795214,"top":0.35993615,"width":0.023105053,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"bounds":{"left":0.54454786,"top":0.35993615,"width":0.023936171,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"bounds":{"left":0.5718085,"top":0.35993615,"width":0.022107713,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"bounds":{"left":0.59391624,"top":0.35993615,"width":0.02044548,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.6156915,"top":0.35913807,"width":0.0029920214,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.6186835,"top":0.35913807,"width":0.030086435,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.6186835,"top":0.35913807,"width":0.030086435,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"bounds":{"left":0.87516624,"top":0.3367917,"width":0.008643617,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"bounds":{"left":0.88181514,"top":0.33838788,"width":0.0019946808,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"testing: update spec from recent changes (2026-05-04)","depth":13,"bounds":{"left":0.49883643,"top":0.38946527,"width":0.14328457,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"testing: update spec from recent changes (2026-05-04)","depth":14,"bounds":{"left":0.49883643,"top":0.38946527,"width":0.14328457,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3223 by","depth":14,"bounds":{"left":0.49883643,"top":0.41181165,"width":0.019115692,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"bounds":{"left":0.51795214,"top":0.41181165,"width":0.023105053,"height":0.011971269},"on_screen":true,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"bounds":{"left":0.51795214,"top":0.41181165,"width":0.023105053,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"bounds":{"left":0.54454786,"top":0.41181165,"width":0.023936171,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"bounds":{"left":0.5718085,"top":0.41181165,"width":0.022107713,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"bounds":{"left":0.59391624,"top":0.41181165,"width":0.02044548,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.6156915,"top":0.41101357,"width":0.0029920214,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.6186835,"top":0.41101357,"width":0.030086435,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.6186835,"top":0.41101357,"width":0.030086435,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"bounds":{"left":0.87516624,"top":0.38906625,"width":0.008643617,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"bounds":{"left":0.88181514,"top":0.3906624,"width":0.0019946808,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"fix: add circuit breaker for corrupted segmentation model","depth":13,"bounds":{"left":0.49883643,"top":0.44173983,"width":0.14494681,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"fix: add circuit breaker for corrupted segmentation model","depth":14,"bounds":{"left":0.49883643,"top":0.44173983,"width":0.14494681,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3222 by","depth":14,"bounds":{"left":0.49883643,"top":0.4640862,"width":0.019115692,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"bounds":{"left":0.51795214,"top":0.4640862,"width":0.023105053,"height":0.011971269},"on_screen":true,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"bounds":{"left":0.51795214,"top":0.4640862,"width":0.023105053,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"bounds":{"left":0.54454786,"top":0.4640862,"width":0.023769947,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"bounds":{"left":0.5718085,"top":0.4640862,"width":0.021941489,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"bounds":{"left":0.59375,"top":0.4640862,"width":0.02044548,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.61552525,"top":0.4632881,"width":0.0029920214,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.6185173,"top":0.4632881,"width":0.03025266,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.6185173,"top":0.4632881,"width":0.03025266,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"2 comments","depth":13,"bounds":{"left":0.8746675,"top":0.44094175,"width":0.009142287,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"2","depth":14,"bounds":{"left":0.8813165,"top":0.4425379,"width":0.002493351,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"docs(testing): add a11y multi-line bbox regression entry","depth":13,"bounds":{"left":0.49883643,"top":0.49401435,"width":0.14112367,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"docs(testing): add a11y multi-line bbox regression entry","depth":14,"bounds":{"left":0.49883643,"top":0.49401435,"width":0.14112367,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3221 by","depth":14,"bounds":{"left":0.49883643,"top":0.51636076,"width":0.018450798,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"bounds":{"left":0.51728725,"top":0.51636076,"width":0.023105053,"height":0.011971269},"on_screen":true,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"bounds":{"left":0.51728725,"top":0.51636076,"width":0.023105053,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"bounds":{"left":0.54388297,"top":0.51636076,"width":0.023936171,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"bounds":{"left":0.5711436,"top":0.51636076,"width":0.022107713,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"bounds":{"left":0.59325135,"top":0.51636076,"width":0.02044548,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.6150266,"top":0.51556265,"width":0.0029920214,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.6180186,"top":0.51556265,"width":0.030086435,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.6180186,"top":0.51556265,"width":0.030086435,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"bounds":{"left":0.87516624,"top":0.49321628,"width":0.008643617,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"bounds":{"left":0.88181514,"top":0.49481246,"width":0.0019946808,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"fix: add diagnostic logging for audio device configuration selection","depth":13,"bounds":{"left":0.49883643,"top":0.54588985,"width":0.16805187,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"fix: add diagnostic logging for audio device configuration selection","depth":14,"bounds":{"left":0.49883643,"top":0.54588985,"width":0.16805187,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3220 by","depth":14,"bounds":{"left":0.49883643,"top":0.56823623,"width":0.019115692,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"bounds":{"left":0.51795214,"top":0.56823623,"width":0.023105053,"height":0.011971269},"on_screen":true,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"bounds":{"left":0.51795214,"top":0.56823623,"width":0.023105053,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"bounds":{"left":0.54454786,"top":0.56823623,"width":0.023936171,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"bounds":{"left":0.5718085,"top":0.56823623,"width":0.022107713,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"bounds":{"left":0.59391624,"top":0.56823623,"width":0.02044548,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.6156915,"top":0.5674381,"width":0.0029920214,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.6186835,"top":0.5674381,"width":0.030086435,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.6186835,"top":0.5674381,"width":0.030086435,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"bounds":{"left":0.87516624,"top":0.5454908,"width":0.008643617,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"bounds":{"left":0.88181514,"top":0.547087,"width":0.0019946808,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"docs: improve SEO titles across generic pages","depth":13,"bounds":{"left":0.49883643,"top":0.5981644,"width":0.116855055,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"docs: improve SEO titles across generic pages","depth":14,"bounds":{"left":0.49883643,"top":0.5981644,"width":0.116855055,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3219 by","depth":14,"bounds":{"left":0.49883643,"top":0.62051076,"width":0.01861702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"mintlify","depth":14,"bounds":{"left":0.51745343,"top":0.62051076,"width":0.013796543,"height":0.011971269},"on_screen":true,"help_text":"pull requests opened by mintlify[bot]","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"mintlify","depth":15,"bounds":{"left":0.51745343,"top":0.62051076,"width":0.013796543,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bot","depth":15,"bounds":{"left":0.5347407,"top":0.62051076,"width":0.0066489363,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was merged","depth":14,"bounds":{"left":0.5437167,"top":0.62051076,"width":0.024933511,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"4 days ago","depth":15,"bounds":{"left":0.56865025,"top":0.62051076,"width":0.020611702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.5905917,"top":0.6197127,"width":0.0029920214,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.59358376,"top":0.6197127,"width":0.030086435,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.59358376,"top":0.6197127,"width":0.030086435,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"bounds":{"left":0.87516624,"top":0.59736633,"width":0.008643617,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"bounds":{"left":0.88181514,"top":0.5989625,"width":0.0019946808,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"changelog: week of may 3, 2026","depth":13,"bounds":{"left":0.49883643,"top":0.6500399,"width":0.08228058,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"changelog: week of may 3, 2026","depth":14,"bounds":{"left":0.49883643,"top":0.6500399,"width":0.08228058,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3218 by","depth":14,"bounds":{"left":0.49883643,"top":0.6723863,"width":0.01861702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"mintlify","depth":14,"bounds":{"left":0.51745343,"top":0.6723863,"width":0.013796543,"height":0.011971269},"on_screen":true,"help_text":"pull requests opened by mintlify[bot]","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"mintlify","depth":15,"bounds":{"left":0.51745343,"top":0.6723863,"width":0.013796543,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bot","depth":15,"bounds":{"left":0.5347407,"top":0.6723863,"width":0.0066489363,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"bounds":{"left":0.5437167,"top":0.6723863,"width":0.023105053,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"bounds":{"left":0.5668218,"top":0.6723863,"width":0.02044548,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.58859706,"top":0.6715882,"width":0.0029920214,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.5915891,"top":0.6715882,"width":0.030086435,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.5915891,"top":0.6715882,"width":0.030086435,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"2 comments","depth":13,"bounds":{"left":0.8746675,"top":0.64964086,"width":0.009142287,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"2","depth":14,"bounds":{"left":0.8813165,"top":0.651237,"width":0.002493351,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"docs(testing): add multi-line text bbox capture regression test","depth":13,"bounds":{"left":0.49883643,"top":0.70231444,"width":0.15741356,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"docs(testing): add multi-line text bbox capture regression test","depth":14,"bounds":{"left":0.49883643,"top":0.70231444,"width":0.15741356,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3217 by","depth":14,"bounds":{"left":0.49883643,"top":0.7246608,"width":0.018284574,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"bounds":{"left":0.517121,"top":0.7246608,"width":0.023271276,"height":0.011971269},"on_screen":true,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"bounds":{"left":0.517121,"top":0.7246608,"width":0.023271276,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"bounds":{"left":0.5437167,"top":0.7246608,"width":0.023936171,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"bounds":{"left":0.5711436,"top":0.7246608,"width":0.021941489,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"bounds":{"left":0.5930851,"top":0.7246608,"width":0.02044548,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.61486036,"top":0.7238627,"width":0.0029920214,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.6178524,"top":0.7238627,"width":0.030086435,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.6178524,"top":0.7238627,"width":0.030086435,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"bounds":{"left":0.87516624,"top":0.7015164,"width":0.008643617,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"bounds":{"left":0.88181514,"top":0.70311254,"width":0.0019946808,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"docs(testing): add Windows GetWindowRect bounds regression test","depth":13,"bounds":{"left":0.49883643,"top":0.75458896,"width":0.17270611,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"docs(testing): add Windows GetWindowRect bounds regression test","depth":14,"bounds":{"left":0.49883643,"top":0.75458896,"width":0.17270611,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3216 by","depth":14,"bounds":{"left":0.49883643,"top":0.77693534,"width":0.01861702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"bounds":{"left":0.51745343,"top":0.77693534,"width":0.023105053,"height":0.011971269},"on_screen":true,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"bounds":{"left":0.51745343,"top":0.77693534,"width":0.023105053,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"bounds":{"left":0.5440492,"top":0.77693534,"width":0.023769947,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"bounds":{"left":0.57130986,"top":0.77693534,"width":0.021941489,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"bounds":{"left":0.59325135,"top":0.77693534,"width":0.020611702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.61519283,"top":0.7761373,"width":0.0029920214,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.61818486,"top":0.7761373,"width":0.030086435,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.61818486,"top":0.7761373,"width":0.030086435,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"bounds":{"left":0.87516624,"top":0.7537909,"width":0.008643617,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"bounds":{"left":0.88181514,"top":0.75538707,"width":0.0019946808,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Fix devcontainer cargo path","depth":13,"bounds":{"left":0.49883643,"top":0.8064645,"width":0.0703125,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Fix devcontainer cargo path","depth":14,"bounds":{"left":0.49883643,"top":0.8064645,"width":0.0703125,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3214 by","depth":14,"bounds":{"left":0.49883643,"top":0.8288109,"width":0.01861702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"julpel8","depth":14,"bounds":{"left":0.51745343,"top":0.8288109,"width":0.012632979,"height":0.011971269},"on_screen":true,"help_text":"pull requests opened by julpel8","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"julpel8","depth":15,"bounds":{"left":0.51745343,"top":0.8288109,"width":0.012632979,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Contributor","depth":16,"bounds":{"left":0.53357714,"top":0.8288109,"width":0.022107713,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was merged","depth":14,"bounds":{"left":0.55917555,"top":0.8288109,"width":0.023936171,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"4 days ago","depth":15,"bounds":{"left":0.5831117,"top":0.8288109,"width":0.02044548,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.60488695,"top":0.82801276,"width":0.0031582448,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.6080452,"top":0.82801276,"width":0.030086435,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.6080452,"top":0.82801276,"width":0.030086435,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"fix(settings): api key regenerate cancel, apply button, manual edit","depth":13,"bounds":{"left":0.49883643,"top":0.858739,"width":0.1662234,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"fix(settings): api key regenerate cancel, apply button, manual edit","depth":14,"bounds":{"left":0.49883643,"top":0.858739,"width":0.1662234,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3212 by","depth":14,"bounds":{"left":0.49883643,"top":0.8810854,"width":0.018450798,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Anshgrover23","depth":14,"bounds":{"left":0.51728725,"top":0.8810854,"width":0.02642952,"height":0.011971269},"on_screen":true,"help_text":"pull requests opened by Anshgrover23","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Anshgrover23","depth":15,"bounds":{"left":0.51728725,"top":0.8810854,"width":0.02642952,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-4824052522680830546
|
-5252347656458365412
|
click
|
accessibility
|
NULL
|
Pull requests · screenpipe/screenpipe · GitHub
Pul Pull requests · screenpipe/screenpipe · GitHub
Pull requests · screenpipe/screenpipe · GitHub
Close tab
Home | Hostinger
Home | Hostinger
Login – Nginx Proxy Manager
Login – Nginx Proxy Manager
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Skip to content
Skip to content
Navigation Menu
Navigation Menu
Homepage
Platform
Solutions
Resources
Open Source
Enterprise
Pricing
Pricing
Search or jump to…
Search or jump to...
Sign in
Sign in
Sign up
Sign up
Appearance settings
screenpipe
screenpipe
/
screenpipe
screenpipe
Public
You must be signed in to change notification settings
Notifications
Fork 1.7k
Fork
1.7k
You must be signed in to star a repository
Star
18.6k
Code
Code
Issues 16
Issues
16
Pull requests 17
Pull requests
17
Discussions
Discussions
Actions
Actions
Projects
Projects
Security and quality
Security and quality
Insights
Insights
Pull requests: screenpipe/screenpipe
Pull requests: screenpipe/screenpipe
is:pr is:closed
Labels 43
Labels
43
Milestones 0
Milestones
0
New pull request
New pull request
Clear current search query, filters, and sorts
Clear current search query, filters, and sorts
17 Open
17 Open
1,593 Closed
1,593 Closed
Author
Author
Label
Label
Projects
Projects
Milestones
Milestones
Reviews
Reviews
Assignee
Assignee
Sort
Sort
Pull requests list
Pull requests list
docs(testing): add 3 recent regression test entries
docs(testing): add 3 recent regression test entries
#3224 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
testing: update spec from recent changes (2026-05-04)
testing: update spec from recent changes (2026-05-04)
#3223 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
fix: add circuit breaker for corrupted segmentation model
fix: add circuit breaker for corrupted segmentation model
#3222 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
2 comments
2
docs(testing): add a11y multi-line bbox regression entry
docs(testing): add a11y multi-line bbox regression entry
#3221 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
fix: add diagnostic logging for audio device configuration selection
fix: add diagnostic logging for audio device configuration selection
#3220 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
docs: improve SEO titles across generic pages
docs: improve SEO titles across generic pages
#3219 by
mintlify
mintlify
Bot
was merged
4 days ago
•
Review required before merging
Review required
1 comment
1
changelog: week of may 3, 2026
changelog: week of may 3, 2026
#3218 by
mintlify
mintlify
Bot
was closed
3 days ago
•
Review required before merging
Review required
2 comments
2
docs(testing): add multi-line text bbox capture regression test
docs(testing): add multi-line text bbox capture regression test
#3217 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
docs(testing): add Windows GetWindowRect bounds regression test
docs(testing): add Windows GetWindowRect bounds regression test
#3216 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
Fix devcontainer cargo path
Fix devcontainer cargo path
#3214 by
julpel8
julpel8
Contributor
was merged
4 days ago
•
Review required before merging
Review required
fix(settings): api key regenerate cancel, apply button, manual edit
fix(settings): api key regenerate cancel, apply button, manual edit
#3212 by
Anshgrover23
Anshgrover23...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
10304
|
470
|
43
|
2026-05-08T17:17:41.710067+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778260661710_m2.jpg...
|
Firefox
|
AFFiNE — Personal
|
True
|
app.affine.pro/workspace/M_vDJhnmiED_6JNdL9GEq/jou app.affine.pro/workspace/M_vDJhnmiED_6JNdL9GEq/journals...
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Pull requests · screenpipe/screenpipe · GitHub
Pul Pull requests · screenpipe/screenpipe · GitHub
Pull requests · screenpipe/screenpipe · GitHub
Home | Hostinger
Home | Hostinger
Login – Nginx Proxy Manager
Login – Nginx Proxy Manager
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
AFFiNE - All In One KnowledgeOS
AFFiNE - All In One KnowledgeOS
AFFiNE
AFFiNE
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Open this doc in AFFiNE app
Don't have the app?
Click to download
Click to download
.
Remember choice
Remember choice
Remember choice
Dismiss
Dismiss
Open in app
Open in app
Demo Workspace Syncing...
Demo Workspace
Syncing...
Lukáš Koválik
Search
All docs
All docs
Journals
Journals
Notifications
Intelligence
Intelligence
Settings
Favorites
Favorites
No favorites
Organize
Organize
First Folder
Tags
Tags
Collections
Collections
Others
Others
Trash
Trash
Import
Template
Learn more
Learn more
Download App
Download App
2026-05-03
Sun
3
2026-05-04
Mon
4
2026-05-05
Tue
5
2026-05-06
Wed
6
2026-05-07
Thu
7
2026-05-08
Fri
8
2026-05-09
Sat
9
May 8, 2026
Today
No Journal
Create Daily Journal
Create Daily Journal...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Pull requests · screenpipe/screenpipe · GitHub","depth":4,"bounds":{"left":0.26097074,"top":0.0518755,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests · screenpipe/screenpipe · GitHub","depth":5,"bounds":{"left":0.27426863,"top":0.06304868,"width":0.080784574,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Home | Hostinger","depth":4,"bounds":{"left":0.26097074,"top":0.08459697,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Home | Hostinger","depth":5,"bounds":{"left":0.27426863,"top":0.09577015,"width":0.03025266,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Login – Nginx Proxy Manager","depth":4,"bounds":{"left":0.26097074,"top":0.11731844,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Login – Nginx Proxy Manager","depth":5,"bounds":{"left":0.27426863,"top":0.12849163,"width":0.05069814,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Screenpipe — Archive","depth":4,"bounds":{"left":0.26097074,"top":0.15003991,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Screenpipe — Archive","depth":5,"bounds":{"left":0.27426863,"top":0.16121309,"width":0.037898935,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: archive.db","depth":4,"bounds":{"left":0.26097074,"top":0.18276137,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: archive.db","depth":5,"bounds":{"left":0.27426863,"top":0.19393456,"width":0.040724736,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: db.sqlite","depth":4,"bounds":{"left":0.26097074,"top":0.21548285,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: db.sqlite","depth":5,"bounds":{"left":0.27426863,"top":0.22665602,"width":0.03756649,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub","depth":4,"bounds":{"left":0.26097074,"top":0.2482043,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub","depth":5,"bounds":{"left":0.27426863,"top":0.25937748,"width":0.11469415,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"DXP4800PLUS-B5F8","depth":4,"bounds":{"left":0.26097074,"top":0.28092578,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"DXP4800PLUS-B5F8","depth":5,"bounds":{"left":0.27426863,"top":0.29209897,"width":0.036901597,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Оптичен интернет за дома - EON телевизия | Vivacom | 5G","depth":4,"bounds":{"left":0.26097074,"top":0.31364724,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Оптичен интернет за дома - EON телевизия | Vivacom | 5G","depth":5,"bounds":{"left":0.27426863,"top":0.32482043,"width":0.105884306,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"AFFiNE - All In One KnowledgeOS","depth":4,"bounds":{"left":0.26097074,"top":0.3463687,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AFFiNE - All In One KnowledgeOS","depth":5,"bounds":{"left":0.27426863,"top":0.3575419,"width":0.05851064,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"AFFiNE","depth":4,"bounds":{"left":0.26097074,"top":0.3790902,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"AFFiNE","depth":5,"bounds":{"left":0.27426863,"top":0.39026338,"width":0.012466756,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.36236703,"top":0.38627294,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.26379654,"top":0.41340783,"width":0.108211435,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.26379654,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"bounds":{"left":0.27476728,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.28590426,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.29704124,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bitwarden","depth":6,"bounds":{"left":0.3081782,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Open this doc in AFFiNE app","depth":9,"bounds":{"left":0.6364694,"top":1.0,"width":0.0631649,"height":-0.082601786},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Don't have the app?","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Click to download","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Click to download","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Remember choice","depth":10,"on_screen":false,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Remember choice","depth":11,"on_screen":false,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Remember choice","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Dismiss","depth":9,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Dismiss","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Open in app","depth":9,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Open in app","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Demo Workspace Syncing...","depth":10,"bounds":{"left":0.3773271,"top":0.101356745,"width":0.06565824,"height":0.023942538},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXStaticText","text":"Demo Workspace","depth":16,"bounds":{"left":0.38863033,"top":0.10654429,"width":0.0390625,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Syncing...","depth":16,"bounds":{"left":0.39461437,"top":0.12410215,"width":0.02144282,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Lukáš Koválik","depth":10,"bounds":{"left":0.44564494,"top":0.105347164,"width":0.0066489363,"height":0.015961692},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Search","depth":12,"bounds":{"left":0.3899601,"top":0.13846768,"width":0.015292553,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"All docs","depth":10,"bounds":{"left":0.3793218,"top":0.16041501,"width":0.072972074,"height":0.023942538},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"All docs","depth":13,"bounds":{"left":0.3899601,"top":0.16560255,"width":0.017287234,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Journals","depth":10,"bounds":{"left":0.3793218,"top":0.18435754,"width":0.072972074,"height":0.027134877},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Journals","depth":13,"bounds":{"left":0.3899601,"top":0.19273743,"width":0.01861702,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Notifications","depth":12,"bounds":{"left":0.3899601,"top":0.21987231,"width":0.027759308,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Intelligence","depth":10,"bounds":{"left":0.3793218,"top":0.2386273,"width":0.072972074,"height":0.027134877},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Intelligence","depth":13,"bounds":{"left":0.3899601,"top":0.24700718,"width":0.025265958,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Settings","depth":12,"bounds":{"left":0.3899601,"top":0.27414206,"width":0.018118352,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Favorites","depth":11,"bounds":{"left":0.3773271,"top":0.30247405,"width":0.076961435,"height":0.015961692},"on_screen":true,"help_text":"","role_description":"switch","subrole":"AXSwitch","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Favorites","depth":12,"bounds":{"left":0.3799867,"top":0.3044693,"width":0.01761968,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"No favorites","depth":14,"bounds":{"left":0.40242687,"top":0.36671987,"width":0.026761968,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Organize","depth":11,"bounds":{"left":0.3773271,"top":0.3982442,"width":0.076961435,"height":0.015961692},"on_screen":true,"help_text":"","role_description":"switch","subrole":"AXSwitch","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Organize","depth":12,"bounds":{"left":0.3799867,"top":0.40023944,"width":0.017121011,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"First Folder","depth":15,"bounds":{"left":0.3899601,"top":0.42577812,"width":0.024767287,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Tags","depth":11,"bounds":{"left":0.3773271,"top":0.4509178,"width":0.076961435,"height":0.015961692},"on_screen":true,"help_text":"","role_description":"switch","subrole":"AXSwitch","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Tags","depth":12,"bounds":{"left":0.3799867,"top":0.45291302,"width":0.009142287,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Collections","depth":11,"bounds":{"left":0.3773271,"top":0.47326416,"width":0.076961435,"height":0.015961692},"on_screen":true,"help_text":"","role_description":"switch","subrole":"AXSwitch","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Collections","depth":12,"bounds":{"left":0.3799867,"top":0.47525936,"width":0.021276595,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Others","depth":11,"bounds":{"left":0.3773271,"top":0.49561054,"width":0.076961435,"height":0.015961692},"on_screen":true,"help_text":"","role_description":"switch","subrole":"AXSwitch","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Others","depth":12,"bounds":{"left":0.3799867,"top":0.49760574,"width":0.012965426,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Trash","depth":12,"bounds":{"left":0.3799867,"top":0.52394253,"width":0.07164229,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Trash","depth":15,"bounds":{"left":0.390625,"top":0.5215483,"width":0.012300532,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Import","depth":14,"bounds":{"left":0.390625,"top":0.54868317,"width":0.014461436,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Template","depth":15,"bounds":{"left":0.390625,"top":0.57581806,"width":0.020279255,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Learn more","depth":12,"bounds":{"left":0.3799867,"top":0.60534716,"width":0.07164229,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Learn more","depth":15,"bounds":{"left":0.390625,"top":0.6029529,"width":0.024933511,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Download App","depth":10,"bounds":{"left":0.3793218,"top":0.9489226,"width":0.072972074,"height":0.0415004},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Download App","depth":12,"bounds":{"left":0.39960107,"top":0.9628891,"width":0.032081116,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"2026-05-03","depth":11,"bounds":{"left":0.5969083,"top":0.057063047,"width":0.034242023,"height":0.0311253},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sun","depth":13,"bounds":{"left":0.61037236,"top":0.05905826,"width":0.00731383,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3","depth":13,"bounds":{"left":0.61269945,"top":0.07342378,"width":0.0026595744,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"2026-05-04","depth":11,"bounds":{"left":0.63248,"top":0.057063047,"width":0.034075797,"height":0.0311253},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Mon","depth":13,"bounds":{"left":0.6452792,"top":0.05905826,"width":0.008477394,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"4","depth":13,"bounds":{"left":0.64827126,"top":0.07342378,"width":0.002493351,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"2026-05-05","depth":11,"bounds":{"left":0.66788566,"top":0.057063047,"width":0.034242023,"height":0.0311253},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Tue","depth":13,"bounds":{"left":0.68151593,"top":0.05905826,"width":0.006981383,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5","depth":13,"bounds":{"left":0.6838431,"top":0.07342378,"width":0.002493351,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"2026-05-06","depth":11,"bounds":{"left":0.7034575,"top":0.057063047,"width":0.034242023,"height":0.0311253},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Wed","depth":13,"bounds":{"left":0.7162567,"top":0.05905826,"width":0.008643617,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"6","depth":13,"bounds":{"left":0.71924865,"top":0.07342378,"width":0.0026595744,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"2026-05-07","depth":11,"bounds":{"left":0.7390292,"top":0.057063047,"width":0.034242023,"height":0.0311253},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Thu","depth":13,"bounds":{"left":0.7524933,"top":0.05905826,"width":0.00731383,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"7","depth":13,"bounds":{"left":0.7549867,"top":0.07342378,"width":0.0023271276,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"2026-05-08","depth":11,"bounds":{"left":0.77460104,"top":0.057063047,"width":0.034075797,"height":0.0311253},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Fri","depth":13,"bounds":{"left":0.78922874,"top":0.05905826,"width":0.0048204786,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"8","depth":13,"bounds":{"left":0.7903923,"top":0.07342378,"width":0.002493351,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"2026-05-09","depth":11,"bounds":{"left":0.8100067,"top":0.057063047,"width":0.034242023,"height":0.0311253},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sat","depth":13,"bounds":{"left":0.8239694,"top":0.05905826,"width":0.0063164895,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"9","depth":13,"bounds":{"left":0.8259641,"top":0.07342378,"width":0.002493351,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"May 8, 2026","depth":12,"bounds":{"left":0.579621,"top":0.12410215,"width":0.08028591,"height":0.039106146},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Today","depth":12,"bounds":{"left":0.6625665,"top":0.13806863,"width":0.021609042,"height":0.021548284},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"No Journal","depth":12,"bounds":{"left":0.7165891,"top":0.26536313,"width":0.023936171,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Create Daily Journal","depth":11,"bounds":{"left":0.70495343,"top":0.29369512,"width":0.04720745,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Create Daily Journal","depth":13,"bounds":{"left":0.70927525,"top":0.2988827,"width":0.03856383,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
5564194284655003331
|
-8766599021656435197
|
click
|
accessibility
|
NULL
|
Pull requests · screenpipe/screenpipe · GitHub
Pul Pull requests · screenpipe/screenpipe · GitHub
Pull requests · screenpipe/screenpipe · GitHub
Home | Hostinger
Home | Hostinger
Login – Nginx Proxy Manager
Login – Nginx Proxy Manager
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
AFFiNE - All In One KnowledgeOS
AFFiNE - All In One KnowledgeOS
AFFiNE
AFFiNE
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Open this doc in AFFiNE app
Don't have the app?
Click to download
Click to download
.
Remember choice
Remember choice
Remember choice
Dismiss
Dismiss
Open in app
Open in app
Demo Workspace Syncing...
Demo Workspace
Syncing...
Lukáš Koválik
Search
All docs
All docs
Journals
Journals
Notifications
Intelligence
Intelligence
Settings
Favorites
Favorites
No favorites
Organize
Organize
First Folder
Tags
Tags
Collections
Collections
Others
Others
Trash
Trash
Import
Template
Learn more
Learn more
Download App
Download App
2026-05-03
Sun
3
2026-05-04
Mon
4
2026-05-05
Tue
5
2026-05-06
Wed
6
2026-05-07
Thu
7
2026-05-08
Fri
8
2026-05-09
Sat
9
May 8, 2026
Today
No Journal
Create Daily Journal
Create Daily Journal...
|
10302
|
NULL
|
NULL
|
NULL
|
|
10321
|
469
|
43
|
2026-05-08T17:18:18.121857+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778260698121_m1.jpg...
|
Firefox
|
DXP4800PLUS-B5F8 — Personal
|
True
|
nas.lakylak.xyz/desktop/#/
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Pull requests · screenpipe/screenpipe · GitHub
Pul Pull requests · screenpipe/screenpipe · GitHub
Pull requests · screenpipe/screenpipe · GitHub
Home | Hostinger
Home | Hostinger
Login – Nginx Proxy Manager
Login – Nginx Proxy Manager
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
Close tab
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
AFFiNE - All In One KnowledgeOS
AFFiNE - All In One KnowledgeOS
All docs · AFFiNE
All docs · AFFiNE
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
1.4
KB/s
1.3
KB/s
Files
1
Control Panel
Storage
App Center
Logs
Support
Task Manager
Universal Search
Music
Cloud Drives
Theater
Photos
Online Office
TextEdit
Virtual Machine
Downloads
DLNA
File Version Explorer
Security
Jellyfin-HT
SAN Manager
Vault
Snapshot
Comics
Sync & Backup
Control Panel
Search
Connection & Access
User Management
File Service
Device Connection
Domain/LDAP
Terminal
General
Hardware & Power
Time & Language
Network
Security
Indexing Service
Service
About
Update & Restore
1
Telnet
Enable
Enable
Port
23
Advanced settings
SSH
Enable
Enable
Port
22
Shut down automatically
1h later
Advanced settings
Function description
Use a terminal to log in and manage your system. When enabling this function, it is recommended to set a strong password for the login account and enable
auto block
auto block
to enhance system security.
Apply
Tips
Tips
SSH possesses advanced remote management feature, but enabling it for a long term will increase security risks (e.g. potential unauthorized access). To ensure NAS and data security, please only enable SSH when in need
Cancel
Enable...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Pull requests · screenpipe/screenpipe · GitHub","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests · screenpipe/screenpipe · GitHub","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Home | Hostinger","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Home | Hostinger","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Login – Nginx Proxy Manager","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Login – Nginx Proxy Manager","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Screenpipe — Archive","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Screenpipe — Archive","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: archive.db","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: archive.db","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: db.sqlite","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: db.sqlite","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"DXP4800PLUS-B5F8","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"DXP4800PLUS-B5F8","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Оптичен интернет за дома - EON телевизия | Vivacom | 5G","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Оптичен интернет за дома - EON телевизия | Vivacom | 5G","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"AFFiNE - All In One KnowledgeOS","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AFFiNE - All In One KnowledgeOS","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"All docs · AFFiNE","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"All docs · AFFiNE","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.0,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"bounds":{"left":0.009375,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.03263889,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.05590278,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bitwarden","depth":6,"bounds":{"left":0.079166666,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1.4","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"KB/s","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1.3","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"KB/s","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Files","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Control Panel","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Storage","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"App Center","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Logs","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Support","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Task Manager","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Universal Search","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Music","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Cloud Drives","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Theater","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Photos","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online Office","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"TextEdit","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Virtual Machine","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Downloads","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"DLNA","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"File Version Explorer","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Security","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Jellyfin-HT","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SAN Manager","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Vault","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Snapshot","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Comics","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Sync & Backup","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Control Panel","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXTextField","text":"Search","depth":15,"on_screen":true,"help_text":"","role_description":"text field","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Connection & Access","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"User Management","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"File Service","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Device Connection","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Domain/LDAP","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Terminal","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"General","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Hardware & Power","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Time & Language","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Network","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Security","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Indexing Service","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Service","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"About","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Update & Restore","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Telnet","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Enable","depth":15,"on_screen":true,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Enable","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Port","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXTextField","text":"23","depth":15,"on_screen":true,"value":"23","help_text":"","role_description":"text field","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Advanced settings","depth":15,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SSH","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Enable","depth":15,"on_screen":true,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":true,"is_selected":false},{"role":"AXStaticText","text":"Enable","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Port","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXTextField","text":"22","depth":17,"on_screen":true,"value":"22","help_text":"","role_description":"text field","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Shut down automatically","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1h later","depth":19,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"","depth":19,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Advanced settings","depth":15,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Function description","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Use a terminal to log in and manage your system. When enabling this function, it is recommended to set a strong password for the login account and enable","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"auto block","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"auto block","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to enhance system security.","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Apply","depth":15,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":20,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Tips","depth":18,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Tips","depth":19,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SSH possesses advanced remote management feature, but enabling it for a long term will increase security risks (e.g. potential unauthorized access). To ensure NAS and data security, please only enable SSH when in need","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Cancel","depth":16,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Enable","depth":16,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false}]...
|
-7637089122486512587
|
-9056025082613938417
|
click
|
accessibility
|
NULL
|
Pull requests · screenpipe/screenpipe · GitHub
Pul Pull requests · screenpipe/screenpipe · GitHub
Pull requests · screenpipe/screenpipe · GitHub
Home | Hostinger
Home | Hostinger
Login – Nginx Proxy Manager
Login – Nginx Proxy Manager
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
Close tab
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
AFFiNE - All In One KnowledgeOS
AFFiNE - All In One KnowledgeOS
All docs · AFFiNE
All docs · AFFiNE
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
1.4
KB/s
1.3
KB/s
Files
1
Control Panel
Storage
App Center
Logs
Support
Task Manager
Universal Search
Music
Cloud Drives
Theater
Photos
Online Office
TextEdit
Virtual Machine
Downloads
DLNA
File Version Explorer
Security
Jellyfin-HT
SAN Manager
Vault
Snapshot
Comics
Sync & Backup
Control Panel
Search
Connection & Access
User Management
File Service
Device Connection
Domain/LDAP
Terminal
General
Hardware & Power
Time & Language
Network
Security
Indexing Service
Service
About
Update & Restore
1
Telnet
Enable
Enable
Port
23
Advanced settings
SSH
Enable
Enable
Port
22
Shut down automatically
1h later
Advanced settings
Function description
Use a terminal to log in and manage your system. When enabling this function, it is recommended to set a strong password for the login account and enable
auto block
auto block
to enhance system security.
Apply
Tips
Tips
SSH possesses advanced remote management feature, but enabling it for a long term will increase security risks (e.g. potential unauthorized access). To ensure NAS and data security, please only enable SSH when in need
Cancel
Enable...
|
10319
|
NULL
|
NULL
|
NULL
|
|
10413
|
472
|
43
|
2026-05-08T17:22:46.332212+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778260966332_m2.jpg...
|
Firefox
|
Sign in — Personal
|
True
|
login.lakylak.xyz/login?login_challenge=kpOlHT7s67 login.lakylak.xyz/login?login_challenge=kpOlHT7s6783xLS81fO_Nm3nitbGs8bEY9GAfAQEe6lEKxlIY9WT1QWw4SbHKsZYmfLb4q7k38btW011k8w5x8t4E7yWfK6y93nOqhw6uIolIKVtyXEVdrqMvjA1IdlYa2H66yC_UZmHetoQqbKXmuwvB26r6glol0DvfcEfKCfnkhb7hauMeSaQTnrS5KP5Y8f39DE7QpKXf6hsmhwnYJE2emxxOtH6mK865T4pcuBWeA3mgxJM6NUGNq8QQ3KqvVTIVnRpA_WuL0Dv68kZL-TlN0pNPj6x-jP_1BwnerRvPdVxRI8K5nOGWosEqLt0nPjerwoohifc3dz0BQduga49w-N6RZEZRAeZ2XbBhLa76GXVINYoQ-BS-2PQA2HULqe7evq_SQfW0QJ03yTHSMZLMT0DPDcUpD0F1dq7RXf_tcZbQpgRXvs2oCBjp7Vh_EpYQ7Nqo8NqqTBkPK59m9zFe1UTGxE6lgOtlHIMFglUg0UtUtZPJq05YpIY44L2EodKSCSQTY9jU0iwA_5WRiBYPWOUYKGmSH9fz9qlUv8l1YhJKr9Df0_aESJlMVirYdBglarOINKW5WbnjLYi-VzKBo5KzdzQ8ClVYHBfwJhuf5mJiqiZSBtzT_dMEcR8fbMaG6_ZOeQ70fQ_X1XESXiOCExFjbh4NAi9tHrexcJ7J22-CEJWJqo3JuhfQXNpKDlSE-fpYfuaVAdbISqxVRRHPUSiixBZ81fyQ_E3prCSvX8DTrcmi5nKtsX27-JEH5qizl2gKY-In-t69r0UgbrK3cmGg271FAjhCdg8dbAlCL6UqOTHmYP2D_dUD9K6cjwXcmtYMN9Z0KbWAqvdbnWojwkjV8D0U3QgXjCBh8jrb7ImAb1lahKpuCAKXs8UyR-UST33n2xbckSeiE6mAgWr_27hSobwUfpeM-1Dw_jmQuhnZroSAMVq3Ira9bobTnkXc-OvjD09qXbFmklXptzpbDIPfS6qXDgO39YWR1sTWgoUGm6pVseEO_dvYsLo5yVcGRaLKq467Ffcj_3ydSTNKzwuLXD6PSUZvVc4jG_S7vAmoyzmCFIqPDfuQIgQzOdCz0HIwwAS2uHoN1wftQYCB1ZNTF3JFN3S1NWqKaGayBJGxcuGH6cBdOZvItcYHvzxjY02zI-XoKBgLHJx5MQmMFhg-Iwdlvopw7V6djzzfhFel9Mc5LmcRTpz9QfYYStd1S_8o2sFPjX_dotocuHKUcqRSwQc3IWSq4eX2UOBgX7rGrzDF33unq9CJbiTi0br2qDRcPotNQ%3D%3D...
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Pull requests · screenpipe/screenpipe · GitHub
Pul Pull requests · screenpipe/screenpipe · GitHub
Pull requests · screenpipe/screenpipe · GitHub
Home | Hostinger
Home | Hostinger
Nginx Proxy Manager
Nginx Proxy Manager
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
AFFiNE - All In One KnowledgeOS
AFFiNE - All In One KnowledgeOS
All docs · AFFiNE
All docs · AFFiNE
Sign in
Sign in
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Sign in
Sign in
payments-logger is requesting access
Username
Password
Continue...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Pull requests · screenpipe/screenpipe · GitHub","depth":4,"bounds":{"left":0.5,"top":0.0518755,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests · screenpipe/screenpipe · GitHub","depth":5,"bounds":{"left":0.51329786,"top":0.06304868,"width":0.080784574,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Home | Hostinger","depth":4,"bounds":{"left":0.5,"top":0.08459697,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Home | Hostinger","depth":5,"bounds":{"left":0.51329786,"top":0.09577015,"width":0.03025266,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Nginx Proxy Manager","depth":4,"bounds":{"left":0.5,"top":0.11731844,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Nginx Proxy Manager","depth":5,"bounds":{"left":0.51329786,"top":0.12849163,"width":0.036901597,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Screenpipe — Archive","depth":4,"bounds":{"left":0.5,"top":0.15003991,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Screenpipe — Archive","depth":5,"bounds":{"left":0.51329786,"top":0.16121309,"width":0.037898935,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: archive.db","depth":4,"bounds":{"left":0.5,"top":0.18276137,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: archive.db","depth":5,"bounds":{"left":0.51329786,"top":0.19393456,"width":0.040724736,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: db.sqlite","depth":4,"bounds":{"left":0.5,"top":0.21548285,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: db.sqlite","depth":5,"bounds":{"left":0.51329786,"top":0.22665602,"width":0.03756649,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub","depth":4,"bounds":{"left":0.5,"top":0.2482043,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub","depth":5,"bounds":{"left":0.51329786,"top":0.25937748,"width":0.11469415,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"DXP4800PLUS-B5F8","depth":4,"bounds":{"left":0.5,"top":0.28092578,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"DXP4800PLUS-B5F8","depth":5,"bounds":{"left":0.51329786,"top":0.29209897,"width":0.036901597,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Оптичен интернет за дома - EON телевизия | Vivacom | 5G","depth":4,"bounds":{"left":0.5,"top":0.31364724,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Оптичен интернет за дома - EON телевизия | Vivacom | 5G","depth":5,"bounds":{"left":0.51329786,"top":0.32482043,"width":0.105884306,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"AFFiNE - All In One KnowledgeOS","depth":4,"bounds":{"left":0.5,"top":0.3463687,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AFFiNE - All In One KnowledgeOS","depth":5,"bounds":{"left":0.51329786,"top":0.3575419,"width":0.05851064,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"All docs · AFFiNE","depth":4,"bounds":{"left":0.5,"top":0.3790902,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"All docs · AFFiNE","depth":5,"bounds":{"left":0.51329786,"top":0.39026338,"width":0.029587766,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Sign in","depth":4,"bounds":{"left":0.5,"top":0.41181165,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Sign in","depth":5,"bounds":{"left":0.51329786,"top":0.42298484,"width":0.011635638,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.60139626,"top":0.41899443,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.5028258,"top":0.4461293,"width":0.108211435,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.5028258,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"bounds":{"left":0.51379657,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.5249335,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.53607047,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bitwarden","depth":6,"bounds":{"left":0.5472075,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Sign in","depth":6,"bounds":{"left":0.7569814,"top":0.41181165,"width":0.099734046,"height":0.021548284},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Sign in","depth":7,"bounds":{"left":0.7569814,"top":0.41181165,"width":0.0234375,"height":0.021548284},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"payments-logger is requesting access","depth":7,"bounds":{"left":0.7569814,"top":0.45251396,"width":0.080119684,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Username","depth":8,"bounds":{"left":0.7569814,"top":0.4848364,"width":0.02144282,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Password","depth":8,"bounds":{"left":0.7569814,"top":0.54588985,"width":0.020113032,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Continue","depth":7,"bounds":{"left":0.7569814,"top":0.60734236,"width":0.099734046,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false}]...
|
4790751073278730901
|
-8767224025297447141
|
visual_change
|
accessibility
|
NULL
|
Pull requests · screenpipe/screenpipe · GitHub
Pul Pull requests · screenpipe/screenpipe · GitHub
Pull requests · screenpipe/screenpipe · GitHub
Home | Hostinger
Home | Hostinger
Nginx Proxy Manager
Nginx Proxy Manager
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
AFFiNE - All In One KnowledgeOS
AFFiNE - All In One KnowledgeOS
All docs · AFFiNE
All docs · AFFiNE
Sign in
Sign in
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Sign in
Sign in
payments-logger is requesting access
Username
Password
Continue...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
10640
|
478
|
43
|
2026-05-08T17:36:43.790151+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778261803790_m2.jpg...
|
Code
|
Review payment logger au… — docker [SSH: nas]
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Explorer (⇧⌘E)
Search (⇧⌘F)
Source Control (⌃⇧ Explorer (⇧⌘E)
Search (⇧⌘F)
Source Control (⌃⇧G) - 55 pending changes
55
Run and Debug (⇧⌘D)
Remote Explorer
Extensions (⇧⌘X) - 2 require update
2
Claude Code
Containers
EXPLORER
EXPLORER
Explorer Section: docker [SSH: nas]
Explorer Section: docker [SSH: nas]
DOCKER [SSH: NAS]
audiobookshelf
auth
beszel
bitwarden
dawarich
dsk-uploader
flask-app
garmin-connector
gitea
health
health-tracker
homarr
hst
immich
jellyfinht
kavita
libreoffice
linkwarden
location-logger
alembic
app
mcp-server
.env
.env.example
.gitignore
.mcp.json
M
alembic.ini
docker-compose.yml
M
Dockerfile
README.md
M
requirements.txt
M
today_map.html
mariadb
meeting-detector
mindfulmama
n8n
notifier-app
npm
oauth
obsidian
ollama
open-webui
openttd
openvpn-client
orchestrator
outfit-app
owntracks-stack
paperlessngx
payments-logger
.claude
Outline Section
OUTLINE
OUTLINE
Timeline Section
TIMELINE
TIMELINE
docker-compose.yml, Editor Group 1
docker-compose.yml, Editor Group 1
Review payment logger au…, Editor Group 2
remote SSH: nas
SSH: nas
location-logger (Git)
location-logger
location-logger (Git) - main*, Checkout Branch/Tag...
main*
location-logger (Git) - Synchronize Changes
No Problems
0
0
No Ports Forwarded
0
Notifications
Sign In
Sign In
collapsed
Clear
Review payment logger authorization implementation
Session history
New session
Message actions
review payment_logger project how toes authorization work
Thinking
Thinking
Let me explore the payment_logger project structure first.
Bash
Find payment_logger project files
IN
find /volume2/docker -type f -name "*.py" -o -name "*.yml" -o -name "*.yaml" -o -name "*.env" -o -name "*.toml" -o -name "*.cfg" | grep -i payment | head -50
Copy code to clipboard
OUT
bfs: error: /volume2/docker/portnotedb/pg_commit_ts: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_dynshmem: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_notify: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_serial: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_snapshots: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_subtrans: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_twophase: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_multixact: Permission denied.
bfs: error: /volume2/docker/portnotedb/base: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_replslot: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_tblspc: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_stat: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_stat_tmp: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_xact: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_logical: Permission denied.
bfs: error: /volume2/docker/openttd/.dbus: Permission denied.
bfs: error: /volume2/docker/immich/db: Permission denied.
bfs: error: /volume2/docker/paperlessngx/db: Permission denied.
bfs: error: /volume2/docker/appflowy/postgres: Permission denied.
bfs: error: /volume2/docker/auth/db: Permission denied.
bfs: error: /volume2/docker/openttd/.XDG/dbus-1: Permission denied.
bfs: error: /volume2/docker/openttd/.config/pulse: Permission denied.
bfs: error: /volume2/docker/openttd/.cache/openbox/sessions: Permission denied.
/volume2/docker/payments-logger/.env
/volume2/docker/payments-logger/docker-compose.yml
/volume2/docker/payments-logger/backend/prisma/migrations/migration_lock.toml
Bash
List docker directory contents
IN
ls /volume2/docker/
Copy code to clipboard
OUT
adguard
ai-stack
app-db
appflowy
audiobookshelf
auth
beszel
bitwarden
dawarich
dsk-uploader
flask-app
garmin-connector
gitea
health
health-tracker
homarr
hst
immich
jellyfinht
kavita
libreoffice
linkwarden
location-logger
mariadb
meeting-detector
mindfulmama
n8n
notifier-app
npm
oauth
obsidian
ollama
openttd
openvpn-client
open-webui
orchestrator
outfit-app
owntracks-stack
paperlessngx
payments-logger
personal-log
personal-log-system
player
portainer
portnotedb
reminders-app
romm
second-brain
static
stirling
syncthing
tailscale
temp-logger
test-app
tmp
torrent-stack
tree
trilium
tubearchivist
twenty
uptimekuma
ytptube
Agent:
Explore payment_logger authorization code
IN
Explore the payments-logger project at /volume2/docker/payments-logger and give me a thorough understanding of how authorization works. I need to know:
1. What auth mechanism is used (JWT, sessions, API keys, OAuth, etc.)
2. Where auth is enforced (middleware, decorators, route guards, etc.)
3. What roles/permissions exist
4. How tokens are issued, validated, and refreshed
5. Any auth-related config (env vars, settings)
Please read the key source files and give me a clear summary with file paths and line numbers for the important parts.
Bash
IN
find /volume2/docker/payments-logger -type f -name "*.py" -o -name "*.json" -o -name "*.yml" -o -name "*.yaml" | grep -E "(auth|token|jwt|session|permission|role)" | head -20
Copy code to clipboard
OUT
(Bash completed with no output)
Bash
IN
ls -la /volume2/docker/payments-logger/ 2>/dev/null || echo "Directory not found"
Copy code to clipboard
OUT
total 36
drwxrwxrwx 1 Adm1n admin 162 Mar 29 18:01 .
drwxrwxrwx 1 root root 1146 Apr 26 18:49 ..
-rwxrwxrwx 1 Adm1n admin 15233 Feb 22 17:08 API.md
drwxrwxrwx 1 Adm1n admin 88 Mar 29 15:41 backend
drwxrwxrwx 1 Adm1n admin 38 Mar 29 17:07 .claude
-rwxrwxrwx 1 Adm1n admin 1502 Mar 29 18:01 docker-compose.yml
-rwxrwxrwx 1 Adm1n admin 1066 Mar 29 15:44 .env
-rwxrwxrwx 1 Adm1n admin 1078 Feb 14 17:53 .env.example
drwxrwxrwx 1 Adm1n admin 194 Mar 29 15:44 frontend
-rwxrwxrwx 1 Adm1n admin 19 Feb 14 17:54 .gitignore
-rwxrwxrwx 1 Adm1n admin 4052 Feb 14 19:06 README.md
Bash
IN
find /volume2/docker/payments-logger/backend -type f | head -30
Copy code to clipboard
OUT
/volume2/docker/payments-logger/backend/Dockerfile
/volume2/docker/payments-logger/backend/.dockerignore
/volume2/docker/payments-logger/backend/package.json
/volume2/docker/payments-logger/backend/prisma/schema.prisma
/volume2/docker/payments-logger/backend/src/parser.js
/volume2/docker/payments-logger/backend/src/index.js
/volume2/docker/payments-logger/backend/src/auth.js
/volume2/docker/payments-logger/backend/prisma/migrations/migration_lock.toml
/volume2/docker/payments-logger/backend/src/routes/payments.js
/volume2/docker/payments-logger/backend/prisma/migrations/20260210_init/migration.sql
/volume2/docker/payments-logger/backend/prisma/migrations/20260210_simplify/migration.sql
/volume2/docker/payments-logger/backend/prisma/migrations/20260222_add_card/migration.sql
Bash
IN
find /volume2/docker/payments-logger -type f \( -name "*.js" -o -name "*.json" -o -name "*.md" \) | sort
Copy code to clipboard
OUT
/volume2/docker/payments-logger/API.md
/volume2/docker/payments-logger/backend/package.json
/volume2/docker/payments-logger/backend/src/auth.js
/volume2/docker/payments-logger/backend/src/index.js
/volume2/docker/payments-logger/backend/src/parser.js
/volume2/docker/payments-logger/backend/src/routes/payments.js
/volume2/docker/payments-logger/.claude/settings.local.json
/volume2/docker/payments-logger/frontend/package.json
/volume2/docker/payments-logger/frontend/postcss.config.js
/volume2/docker/payments-logger/frontend/src/auth.js
/volume2/docker/payments-logger/frontend/tailwind.config.js
/volume2/docker/payments-logger/frontend/vite.config.js
/volume2/docker/payments-logger/README.md
Read
.env
.env
Read
auth.js
auth.js
Read
index.js
index.js
Read
package.json
package.json
Read
auth.js
auth.js
Read
API.md
API.md
Read
payments.js
payments.js
Read
.env.example
.env.example
Read
schema.prisma
schema.prisma
Bash
IN
grep -r "API_KEY\|auth\|token\|oauth\|hydra" /volume2/docker/payments-logger/backend/src --include="*.js" -n
Copy code to clipboard
OUT
/volume2/docker/payments-logger/backend/src/index.js:6:const { bearerTokenMiddleware, wellKnownRouter } = require('./auth');
/volume2/docker/payments-logger/backend/src/index.js:18:// ── OAuth Bearer token auth (skips public paths) ──────────────────────────────
/volume2/docker/payments-logger/backend/src/auth.js:2: * OAuth 2.1 / Hydra JWT authentication for Express.
/volume2/docker/payments-logger/backend/src/auth.js:6: * - wellKnownRouter — serves /.well-known/oauth-* discovery endpoints
/volume2/docker/payments-logger/backend/src/auth.js:33:function sendUnauthorized(res, detail, error = 'invalid_token') {
/volume2/docker/payments-logger/backend/src/auth.js:39: `resource_metadata="${realm}/.well-known/oauth-protected-resource"`,
/volume2/docker/payments-logger/backend/src/auth.js:40: `authorization_server="${HYDRA_PUBLIC_URL}"`,
/volume2/docker/payments-logger/backend/src/auth.js:52: * On success, attaches the decoded payload to req.tokenPayload.
/volume2/docker/payments-logger/backend/src/auth.js:54: * @param {Set<string>} publicPaths Paths to skip auth for.
/volume2/docker/payments-logger/backend/src/auth.js:58: '/.well-known/oauth-protected-resource',
/volume2/docker/payments-logger/backend/src/auth.js:59: '/.well-known/oauth-authorization-server',
/volume2/docker/payments-logger/backend/src/auth.js:66: const auth = req.headers.authorization || '';
/volume2/docker/payments-logger/backend/src/auth.js:67: if (!auth.toLowerCase().startsWith('bearer ')) {
/volume2/docker/payments-logger/backend/src/auth.js:68: return sendUnauthorized(res, 'Bearer token required', 'invalid_request');
/volume2/docker/payments-logger/backend/src/auth.js:71: const token = auth.slice(7).trim();
/volume2/docker/payments-logger/backend/src/auth.js:72: if (!token) {
/volume2/docker/payments-logger/backend/src/auth.js:73: return sendUnauthorized(res, 'Bearer token required', 'invalid_request');
/volume2/docker/payments-logger/backend/src/auth.js:82: const { payload } = await jwtVerify(token, getJwks(), verifyOptions);
/volume2/docker/payments-logger/backend/src/auth.js:83: req.tokenPayload = payload;
/volume2/docker/payments-logger/backend/src/auth.js:87: const error = msg.includes('expired') ? 'invalid_token' : 'invalid_token';
/volume2/docker/payments-logger/backend/src/auth.js:88: sendUnauthorized(res, msg, error);
/volume2/docker/payments-logger/backend/src/auth.js:98:wellKnownRouter.get('/.well-known/oauth-protected-resource', (_req, res) => {
/volume2/docker/payments-logger/backend/src/auth.js:103: authorization_servers: [HYDRA_PUBLIC_URL],
/volume2/docker/payments-logger/backend/src/auth.js:111:wellKnownRouter.get('/.well-known/oauth-authorization-server', async (_req, res) => {
/volume2/docker/payments-logger/backend/src/auth.js:119: authorization_endpoint: doc.authorization_endpoint,
/volume2/docker/payments-logger/backend/src/auth.js:120: token_endpoint: doc.token_endpoint,
/volume2/docker/payments-logger/backend/src/auth.js:123: grant_types_supported: doc.grant_types_supported || ['authorization_code', 'refresh_token'],
/volume2/docker/payments-logger/backend/src/auth.js:124: [API_KEY]: doc.[API_KEY] || ['none', 'client_secret_basic'],
/volume2/docker/payments-logger/backend/src/auth.js:128: id_token_signing_alg_values_supported: doc.id_token_signing_alg_values_supported || ['RS256'],
/volume2/docker/payments-logger/backend/src/routes/payments.js:58:// ── Ingest a payment (public — no auth) ──────────────────────────────────────
Bash
IN
find /volume2/docker/payments-logger/frontend/src -type f -name "*.js" -o -name "*.jsx" -o -name "*.ts" -o -name "*.tsx" | head -20
Copy code to clipboard
OUT
/volume2/docker/payments-logger/frontend/src/main.jsx
/volume2/docker/payments-logger/frontend/src/App.jsx
/volume2/docker/payments-logger/frontend/src/auth.js
/volume2/docker/payments-logger/frontend/src/components/PaymentCard.jsx
/volume2/docker/payments-logger/frontend/src/components/PaymentList.jsx
/volume2/docker/payments-logger/frontend/src/components/FilterBar.jsx
/volume2/docker/payments-logger/frontend/src/components/PaymentTable.jsx
/volume2/docker/payments-logger/frontend/src/components/AuthProvider.jsx
/volume2/docker/payments-logger/frontend/src/components/AuthCallback.jsx
Read
AuthProvider.jsx
AuthProvider.jsx
Read
AuthCallback.jsx
AuthCallback.jsx
Read
App.jsx
App.jsx
Read
main.jsx
main.jsx
Read
vite.config.js
vite.config.js
Bash
IN
grep -r "HYDRA\|VITE" /volume2/docker/payments-logger --include=".env*" -n
Copy code to clipboard
OUT
(Bash completed with no output)
Read
docker-compose.yml
docker-compose.yml
Bash
IN
grep -r "API_KEY" /volume2/docker/payments-logger/backend --include="*.js" -n
Copy code to clipboard
OUT
(Bash completed with no output)
Read
README.md
README.md
Bash
IN
grep -n "HYDRA\|oauth\|TOKEN" /volume2/docker/payments-logger/backend/src/index.js /volume2/docker/payments-logger/backend/src/auth.js | head -40
Copy code to clipboard
OUT
/volume2/docker/payments-logger/backend/src/auth.js:6: * - wellKnownRouter — serves /.well-known/oauth-* discovery endpoints
/volume2/docker/payments-logger/backend/src/auth.js:11:const HYDRA_PUBLIC_URL = (process.env.HYDRA_PUBLIC_URL || '').replace(/\/$/, '');
/volume2/docker/payments-logger/backend/src/auth.js:24: new URL(`${HYDRA_PUBLIC_URL}/.well-known/jwks.json`)
/volume2/docker/payments-logger/backend/src/auth.js:39: `resource_metadata="${realm}/.well-known/oauth-protected-resource"`,
/volume2/docker/payments-logger/backend/src/auth.js:40: `authorization_server="${HYDRA_PUBLIC_URL}"`,
/volume2/docker/payments-logger/backend/src/auth.js:58: '/.well-known/oauth-protected-resource',
/volume2/docker/payments-logger/backend/src/auth.js:59: '/.well-known/oauth-authorization-server',
/volume2/docker/payments-logger/backend/src/auth.js:78: issuer: HYDRA_PUBLIC_URL,
/volume2/docker/payments-logger/backend/src/auth.js:81: if (process.env.TOKEN_AUDIENCE) verifyOptions.audience = process.env.TOKEN_AUDIENCE;
/volume2/docker/payments-logger/backend/src/auth.js:98:wellKnownRouter.get('/.well-known/oauth-protected-resource', (_req, res) => {
/volume2/docker/payments-logger/backend/src/auth.js:103: authorization_servers: [HYDRA_PUBLIC_URL],
/volume2/docker/payments-logger/backend/src/auth.js:107: jwks_uri: `${HYDRA_PUBLIC_URL}/.well-known/jwks.json`,
/volume2/docker/payments-logger/backend/src/auth.js:111:wellKnownRouter.get('/.well-known/oauth-authorization-server', async (_req, res) => {
/volume2/docker/payments-logger/backend/src/auth.js:113: const r = await fetch(`${HYDRA_PUBLIC_URL}/.well-known/openid-configuration`);
/volume2/docker/payments-logger/backend/src/auth.js:118: issuer: doc.issuer || HYDRA_PUBLIC_URL,
Thinking
Thinking
payments-logger Authorization Overview
payments-logger Authorization Overview
The project uses
OAuth 2.1 with PKCE
via an external Hydra OAuth server at
hydra.lakylak.xyz
.
Auth Flow
Auth Flow
Frontend
(
frontend/src/auth.js
frontend/src/auth.js
):
Fetches OAuth server metadata via discovery endpoint
Generates a PKCE code verifier/challenge (SHA-256)
Redirects user to Hydra login with
code_challenge
On callback, exchanges code + verifier for tokens
Stores
access_token
,
refresh_token
in
localStorage
(
pl_oauth_tokens
)
Auto-refreshes token 30 seconds before expiry
Backend
(
backend/src/auth.js
backend/src/auth.js
):
bearerTokenMiddleware
validates the
Authorization: Bearer <token>
header
Fetches Hydra's JWKS (cached 300s) and verifies JWT signature (RS256/ES256/PS256)
Validates issuer (
https://hydra.lakylak.xyz
) and optional audience
Enforcement
Enforcement
Applied globally in
backend/src/index.js:19
backend/src/index.js:19
with these
public (unprotected) paths
:
/.well-known/oauth-protected-resource
/.well-known/oauth-authorization-server
/api/health
/api/payments/ingest
(rate-limited at 200 req/min — for SMS ingestion)
Roles/Permissions
Roles/Permissions
No RBAC
— it's binary: authenticated vs. unauthenticated. Required scopes:
openid
,
offline_access
.
Key Security Notes
Key Security Notes
PKCE
prevents authorization code interception
State parameter
provides CSRF protection
No server-side token storage
— validation is stateless via JWKS
The README/API docs mention an
X-API-Key
header, but that's
outdated
— the actual code uses Bearer tokens only
Config lives in
docker-compose.yml
docker-compose.yml
(lines 30–33):
HYDRA_PUBLIC_URL
,
REQUIRED_SCOPES
,
OAUTH_CLIENT_ID
, and optionally
TOKEN_AUDIENCE
/
JWKS_CACHE_TTL
.
Message actions
compare it to location logger and make it the same. Lets remove hydra and only use authentic (or whatever location logger uses).
Thinking
Thinking
Let me first explore how location-logger handles authorization.
Agent:
Explore location-logger authorization code
IN
Explore the location-logger project at /volume2/docker/location-logger and give me a thorough understanding of how authorization works. I need to know:
1. What auth mechanism is used (JWT, sessions, API keys, OAuth, etc.)
2. Where auth is enforced (middleware, decorators, route guards, etc.)
3. What roles/permissions exist
4. How tokens are issued, validated, and refreshed
5. Any auth-related config (env vars, settings)
6. Frontend auth flow (how the user logs in, how tokens are stored and used)
7. The full directory/file structure of the project
Please read ALL relevant source files completely and give me a detailed summary with file paths and line numbers. I need enough detail to replicate this auth system in another project.
Bash
IN
find /volume2/docker/location-logger -type f -name "*.py" -o -name "*.js" -o -name "*.ts" -o -name "*.json" | head -50
Copy code to clipboard
OUT
/volume2/docker/location-logger/.mcp.json
/volume2/docker/location-logger/app/__init__.py
/volume2/docker/location-logger/app/utils.py
/volume2/docker/location-logger/app/config.py
/volume2/docker/location-logger/app/main.py
/volume2/docker/location-logger/alembic/env.py
/volume2/docker/location-logger/mcp-server/server.py
/volume2/docker/location-logger/alembic/versions/20260203_201500_create_location_points_table.py
/volume2/docker/location-logger/alembic/versions/20260209_200000_add_enhanced_fields_and_tables.py
/volume2/docker/location-logger/alembic/versions/20260214_000000_add_users_and_audit_logs.py
/volume2/docker/location-logger/alembic/versions/20260320_000000_add_audit_query_string.py
/volume2/docker/location-logger/app/services/geofence_service.py
/volume2/docker/location-logger/app/services/recorder_service.py
/volume2/docker/location-logger/app/services/trip_service.py
/volume2/docker/location-logger/app/services/enhanced_location_service.py
/volume2/docker/location-logger/app/services/geocoding_service.py
/volume2/docker/location-logger/app/clients/__init__.py
/volume2/docker/location-logger/app/clients/dawarich_client.py
/volume2/docker/location-logger/app/clients/owntracks_client.py
/volume2/docker/location-logger/app/models/areas.py
/volume2/docker/location-logger/app/models/geofence_events.py
/volume2/docker/location-logger/app/models/trips.py
/volume2/docker/location-logger/app/models/user.py
/volume2/docker/location-logger/app/models/location.py
/volume2/docker/location-logger/app/models/audit_log.py
/volume2/docker/location-logger/app/auth/__init__.py
/volume2/docker/location-logger/app/auth/dependencies.py
/volume2/docker/location-logger/app/auth/utils.py
/volume2/docker/location-logger/app/api/enhanced_endpoints.py
/volume2/docker/location-logger/app/db/base.py
/volume2/docker/location-logger/app/db/session.py
Bash
IN
tree -L 4 /volume2/docker/location-logger 2>/dev/null || find /volume2/docker/location-logger -type d | sort
Copy code to clipboard
OUT
/volume2/docker/location-logger
├── alembic
│ ├── env.py
│ ├── script.py.mako
│ └── versions
│ ├── 20260203_201500_create_location_points_table.py
│ ├── 20260209_200000_add_enhanced_fields_and_tables.py
│ ├── 20260214_000000_add_users_and_audit_logs.py
│ ├── 20260320_000000_add_audit_query_string.py
│ └── __pycache__
│ └── 20260214_000000_add_users_and_audit_logs.cpython-311.pyc
├── alembic.ini
├── app
│ ├── api
│ │ └── enhanced_endpoints.py
│ ├── auth
│ │ ├── dependencies.py
│ │ ├── __init__.py
│ │ ├── __pycache__
│ │ │ ├── dependencies.cpython-311.pyc
│ │ │ ├── __init__.cpython-311.pyc
│ │ │ └── utils.cpython-311.pyc
│ │ └── utils.py
│ ├── clients
│ │ ├── dawarich_client.py
│ │ ├── __init__.py
│ │ └── owntracks_client.py
│ ├── config.py
│ ├── db
│ │ ├── base.py
│ │ └── session.py
│ ├── __init__.py
│ ├── main.py
│ ├── models
│ │ ├── areas.py
│ │ ├── audit_log.py
│ │ ├── geofence_events.py
│ │ ├── location.py
│ │ ├── __pycache__
│ │ │ ├── audit_log.cpython-311.pyc
│ │ │ └── user.cpython-311.pyc
│ │ ├── trips.py
│ │ └── user.py
│ ├── __pycache__
│ │ ├── __init__.cpython-311.pyc
│ │ └── main.cpython-311.pyc
│ ├── services
│ │ ├── enhanced_location_service.py
│ │ ├── geocoding_service.py
│ │ ├── geofence_service.py
│ │ ├── recorder_service.py
│ │ └── trip_service.py
│ ├── static
│ │ └── dashboard.html
│ └── utils.py
├── docker-compose.yml
├── Dockerfile
├── mcp-server
│ ├── Dockerfile
│ ├── requirements.txt
│ └── server.py
├── README.md
├── requirements.txt
└── today_map.html
16 directories, 48 files
Read
utils.py
utils.py
Read
dependencies.py
dependencies.py
Read
user.py
user.py
Read
config.py
config.py
Read
main.py
main.py
Read
session.py
session.py
Read
dashboard.html
dashboard.html
Read
audit_log.py
audit_log.py
Read
20260214_000000_add_users_and_audit_logs.py
20260214_000000_add_users_and_audit_logs.py
Read
20260320_000000_add_audit_query_string.py
20260320_000000_add_audit_query_string.py
Read
README.md
README.md
Read
requirements.txt
requirements.txt
Read
server.py
server.py
Read
server.py
server.py
(lines 101-400)
Thinking
Thinking
Now I have a full picture of both systems. Let me read the payments-logger source files before planning the migration.
Bash
List all payments-logger files
IN
find /volume2/docker/payments-logger -type f | grep -v node_modules | grep -v .git | sort
Copy code to clipboard
OUT
/volume2/docker/payments-logger/API.md
/volume2/docker/payments-logger/backend/Dockerfile
/volume2/docker/payments-logger/backend/.dockerignore
/volume2/docker/payments-logger/backend/package.json
/volume2/docker/payments-logger/backend/prisma/migrations/20260210_init/migration.sql
/volume2/docker/payments-logger/backend/prisma/migrations/20260210_simplify/migration.sql
/volume2/docker/payments-logger/backend/prisma/migrations/20260222_add_card/migration.sql
/volume2/docker/payments-logger/backend/prisma/migrations/migration_lock.toml
/volume2/docker/payments-logger/backend/prisma/schema.prisma
/volume2/docker/payments-logger/backend/src/auth.js
/volume2/docker/payments-logger/backend/src/index.js
/volume2/docker/payments-logger/backend/src/parser.js
/volume2/docker/payments-logger/backend/src/routes/payments.js
/volume2/docker/payments-logger/.claude/settings.local.json
/volume2/docker/payments-logger/docker-compose.yml
/volume2/docker/payments-logger/.env
/volume2/docker/payments-logger/.env.example
/volume2/docker/payments-logger/frontend/Dockerfile
/volume2/docker/payments-logger/frontend/.dockerignore
/volume2/docker/payments-logger/frontend/index.html
/volume2/docker/payments-logger/frontend/package.json
/volume2/docker/payments-logger/frontend/postcss.config.js
/volume2/docker/payments-logger/frontend/src/App.jsx
/volume2/docker/payments-logger/frontend/src/auth.js
/volume2/docker/payments-logger/frontend/src/components/AuthCallback.jsx
/volume2/docker/payments-logger/frontend/src/components/AuthProvider.jsx
/volume2/docker/payments-logger/frontend/src/components/FilterBar.jsx
/volume2/docker/payments-logger/frontend/src/components/PaymentCard.jsx
/volume2/docker/payments-logger/frontend/src/components/PaymentList.jsx
/volume2/docker/payments-logger/frontend/src/components/PaymentTable.jsx
/volume2/docker/payments-logger/frontend/src/index.css
/volume2/docker/payments-logger/frontend/src/main.jsx
/volume2/docker/payments-logger/frontend/tailwind.config.js
/volume2/docker/payments-logger/frontend/vite.config.js
/volume2/docker/payments-logger/README.md
Read
auth.js
auth.js
Read
index.js
index.js
Read
auth.js
auth.js
Read
AuthProvider.jsx
AuthProvider.jsx
Read
package.json
package.json
Read
AuthCallback.jsx
AuthCallback.jsx
Read
schema.prisma
schema.prisma
Read
docker-compose.yml
docker-compose.yml
Thinking
Thinking
Now let me read the remaining frontend files.
Read
App.jsx
App.jsx
Read
package.json
package.json
Read
.env
.env
Thinking
Thinking
Let me read the remaining files before making changes.
Read
main.jsx
main.jsx
Read
vite.config.js
vite.config.js
Read
payments.js
payments.js
Thinking
Thinking
Read
.env.example
.env.example
Thinking
Thinking
Now I have everything I need. Here's what changes:
Backend:
Rewrite
auth.js
(HS256 JWT + bcrypt), add
/auth/login
+
/auth/register
endpoints, add
User
model to Prisma, new migration, remove Hydra env vars.
Frontend:
Replace PKCE flow with a simple login form in
AuthProvider
, simplify
auth.js
, remove
AuthCallback
, drop
/.well-known
proxy.
Config:
Drop all Hydra/OAuth env vars, add
JWT_SECRET
.
Let me implement everything now.
Update Todos
Add bcryptjs to backend package.json
Rewrite backend/src/auth.js (HS256 JWT + bcrypt, login/register routes)
Update backend/src/index.js (remove wellKnownRouter, mount authRouter)
Add User model to prisma/schema.prisma
Create Prisma migration for users table
Rewrite frontend/src/auth.js (simple username/password login)
Rewrite frontend/src/components/AuthProvider.jsx (login form instead of PKCE redirect)
Update frontend/src/main.jsx (remove /auth/callback handling)
Delete frontend/src/components/AuthCallback.jsx
Update frontend/vite.config.js (remove /.well-known proxy)
Update docker-compose.yml (remove Hydra vars/network, add JWT_SECRET)
Update .env and .env.example
Update Todos
Add bcryptjs to backend package.json
Rewrite backend/src/auth.js (HS256 JWT + bcrypt, login/register routes)
Update backend/src/index.js (remove wellKnownRouter, mount authRouter)
Add User model to prisma/schema.prisma
Create Prisma migration for users table
Rewrite frontend/src/auth.js (simple username/password login)
Rewrite frontend/src/components/AuthProvider.jsx (login form instead of PKCE redirect)
Update frontend/src/main.jsx (remove /auth/callback handling)
Delete frontend/src/components/AuthCallback.jsx...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Explorer (⇧⌘E)","depth":19,"bounds":{"left":0.0,"top":0.047885075,"width":0.015957447,"height":0.03830806},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":true},{"role":"AXStaticText","text":"","depth":22,"bounds":{"left":0.0039893617,"top":0.057462092,"width":0.007978723,"height":0.01915403},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Search (⇧⌘F)","depth":19,"bounds":{"left":0.0,"top":0.08619314,"width":0.015957447,"height":0.03830806},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"bounds":{"left":0.0039893617,"top":0.09577015,"width":0.007978723,"height":0.01915403},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Source Control (⌃⇧G) - 55 pending changes","depth":19,"bounds":{"left":0.0,"top":0.1245012,"width":0.015957447,"height":0.03830806},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"bounds":{"left":0.0039893617,"top":0.13407822,"width":0.007978723,"height":0.01915403},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"55","depth":22,"bounds":{"left":0.0076462766,"top":0.1452514,"width":0.0043218085,"height":0.008778931},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Run and Debug (⇧⌘D)","depth":19,"bounds":{"left":0.0,"top":0.16280925,"width":0.015957447,"height":0.03830806},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"bounds":{"left":0.0039893617,"top":0.17238627,"width":0.007978723,"height":0.01915403},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Remote Explorer","depth":19,"bounds":{"left":0.0,"top":0.20111732,"width":0.015957447,"height":0.03830806},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"bounds":{"left":0.0039893617,"top":0.21069433,"width":0.007978723,"height":0.01915403},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Extensions (⇧⌘X) - 2 require update","depth":19,"bounds":{"left":0.0,"top":0.23942538,"width":0.015957447,"height":0.03830806},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"bounds":{"left":0.0039893617,"top":0.2490024,"width":0.007978723,"height":0.01915403},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"2","depth":22,"bounds":{"left":0.009640957,"top":0.2601756,"width":0.0019946808,"height":0.008778931},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Claude Code","depth":19,"bounds":{"left":0.0,"top":0.27773345,"width":0.015957447,"height":0.03830806},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"Containers","depth":19,"bounds":{"left":0.0,"top":0.3160415,"width":0.015957447,"height":0.03830806},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"EXPLORER","depth":17,"bounds":{"left":0.022606382,"top":0.047885075,"width":0.018949468,"height":0.02793296},"on_screen":true,"role_description":"heading"},{"role":"AXStaticText","text":"EXPLORER","depth":18,"bounds":{"left":0.022606382,"top":0.056664005,"width":0.018949468,"height":0.0103751},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.022606382,"top":0.056664005,"width":0.0023271276,"height":0.0103751}},{"char_start":1,"char_count":7,"bounds":{"left":0.024933511,"top":0.056664005,"width":0.01662234,"height":0.0103751}}],"role_description":"text"},{"role":"AXButton","text":"Explorer Section: docker [SSH: nas]","depth":21,"bounds":{"left":0.015957447,"top":0.07581804,"width":0.09940159,"height":0.017557861},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.01662234,"top":0.07821229,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXHeading","text":"Explorer Section: docker [SSH: nas]","depth":22,"bounds":{"left":0.022606382,"top":0.07581804,"width":0.038231384,"height":0.017557861},"on_screen":true,"role_description":"heading"},{"role":"AXStaticText","text":"DOCKER [SSH: NAS]","depth":23,"bounds":{"left":0.022606382,"top":0.079010375,"width":0.038231384,"height":0.0103751},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.022606382,"top":0.07980846,"width":0.0029920214,"height":0.0103751}},{"char_start":1,"char_count":16,"bounds":{"left":0.025598405,"top":0.07980846,"width":0.03523936,"height":0.0103751}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.0933759,"width":0.005319149,"height":0.005586592},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"audiobookshelf","depth":27,"bounds":{"left":0.025930852,"top":0.0933759,"width":0.030917553,"height":0.0047885077},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.103751,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"auth","depth":27,"bounds":{"left":0.025930852,"top":0.103751,"width":0.008976064,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.10454908,"width":0.0023271276,"height":0.011971269}},{"char_start":1,"char_count":3,"bounds":{"left":0.02825798,"top":0.10454908,"width":0.0066489363,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.121308856,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"beszel","depth":27,"bounds":{"left":0.025930852,"top":0.121308856,"width":0.012965426,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.12210695,"width":0.0026595744,"height":0.011971269}},{"char_start":1,"char_count":5,"bounds":{"left":0.028590426,"top":0.12210695,"width":0.010638298,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.13886672,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"bitwarden","depth":27,"bounds":{"left":0.025930852,"top":0.13886672,"width":0.019946808,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.1396648,"width":0.0026595744,"height":0.011971269}},{"char_start":1,"char_count":8,"bounds":{"left":0.028590426,"top":0.1396648,"width":0.017287234,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.15642458,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"dawarich","depth":27,"bounds":{"left":0.025930852,"top":0.15642458,"width":0.017952127,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.15722266,"width":0.0026595744,"height":0.011971269}},{"char_start":1,"char_count":7,"bounds":{"left":0.028590426,"top":0.15722266,"width":0.015625,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.17398244,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"dsk-uploader","depth":27,"bounds":{"left":0.025930852,"top":0.17398244,"width":0.026928192,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.17478053,"width":0.0026595744,"height":0.011971269}},{"char_start":1,"char_count":11,"bounds":{"left":0.028590426,"top":0.17478053,"width":0.024268618,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.10605053,"top":0.17478053,"width":0.004654255,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.1915403,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"flask-app","depth":27,"bounds":{"left":0.025930852,"top":0.1915403,"width":0.018949468,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.19233839,"width":0.0016622341,"height":0.011971269}},{"char_start":1,"char_count":8,"bounds":{"left":0.027593086,"top":0.19233839,"width":0.017287234,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.10605053,"top":0.19233839,"width":0.004654255,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.20909816,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"garmin-connector","depth":27,"bounds":{"left":0.025930852,"top":0.20909816,"width":0.036236703,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.20989625,"width":0.0026595744,"height":0.011971269}},{"char_start":1,"char_count":15,"bounds":{"left":0.028590426,"top":0.20989625,"width":0.033909574,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.22665602,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"gitea","depth":27,"bounds":{"left":0.025930852,"top":0.22665602,"width":0.009973404,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.22745411,"width":0.0026595744,"height":0.011971269}},{"char_start":1,"char_count":4,"bounds":{"left":0.028590426,"top":0.22745411,"width":0.00731383,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.2442139,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"health","depth":27,"bounds":{"left":0.025930852,"top":0.2442139,"width":0.012300532,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.24501197,"width":0.0026595744,"height":0.011971269}},{"char_start":1,"char_count":5,"bounds":{"left":0.028590426,"top":0.24501197,"width":0.009973404,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.26177174,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"health-tracker","depth":27,"bounds":{"left":0.025930852,"top":0.26177174,"width":0.028590426,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.26256984,"width":0.0026595744,"height":0.011971269}},{"char_start":1,"char_count":13,"bounds":{"left":0.028590426,"top":0.26256984,"width":0.025930852,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.2793296,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"homarr","depth":27,"bounds":{"left":0.025930852,"top":0.2793296,"width":0.014295213,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.2801277,"width":0.0026595744,"height":0.011971269}},{"char_start":1,"char_count":5,"bounds":{"left":0.028590426,"top":0.2801277,"width":0.011968086,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.29688746,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"hst","depth":27,"bounds":{"left":0.025930852,"top":0.29688746,"width":0.0063164895,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.29768556,"width":0.0026595744,"height":0.011971269}},{"char_start":1,"char_count":2,"bounds":{"left":0.028590426,"top":0.29768556,"width":0.003656915,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.31444532,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"immich","depth":27,"bounds":{"left":0.025930852,"top":0.31444532,"width":0.01462766,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.31524342,"width":0.0009973404,"height":0.011971269}},{"char_start":1,"char_count":5,"bounds":{"left":0.026928192,"top":0.31524342,"width":0.013630319,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.3320032,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jellyfinht","depth":27,"bounds":{"left":0.025930852,"top":0.3320032,"width":0.016954787,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.33280128,"width":0.0009973404,"height":0.011971269}},{"char_start":1,"char_count":9,"bounds":{"left":0.026928192,"top":0.33280128,"width":0.016289894,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.34956107,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"kavita","depth":27,"bounds":{"left":0.025930852,"top":0.34956107,"width":0.011635638,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.35035914,"width":0.0023271276,"height":0.011971269}},{"char_start":1,"char_count":5,"bounds":{"left":0.02825798,"top":0.35035914,"width":0.009640957,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.36711892,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"libreoffice","depth":27,"bounds":{"left":0.025930852,"top":0.36711892,"width":0.020279255,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.367917,"width":0.0009973404,"height":0.011971269}},{"char_start":1,"char_count":10,"bounds":{"left":0.026928192,"top":0.367917,"width":0.019281914,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.38467678,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"linkwarden","depth":27,"bounds":{"left":0.025930852,"top":0.38467678,"width":0.021609042,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.38547486,"width":0.0009973404,"height":0.011971269}},{"char_start":1,"char_count":9,"bounds":{"left":0.026928192,"top":0.38547486,"width":0.020611702,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.40223464,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"location-logger","depth":27,"bounds":{"left":0.025930852,"top":0.40223464,"width":0.030917553,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.40303272,"width":0.0009973404,"height":0.011971269}},{"char_start":1,"char_count":14,"bounds":{"left":0.026928192,"top":0.40303272,"width":0.029920213,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.10605053,"top":0.40303272,"width":0.004654255,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.022273935,"top":0.4197925,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"alembic","depth":27,"bounds":{"left":0.028590426,"top":0.4197925,"width":0.015625,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.028590426,"top":0.42059058,"width":0.0023271276,"height":0.011971269}},{"char_start":1,"char_count":6,"bounds":{"left":0.030917553,"top":0.42059058,"width":0.013297873,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.10605053,"top":0.42059058,"width":0.004654255,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.022273935,"top":0.43735036,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"app","depth":27,"bounds":{"left":0.028590426,"top":0.43735036,"width":0.0076462766,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.028590426,"top":0.43814844,"width":0.0023271276,"height":0.011971269}},{"char_start":1,"char_count":2,"bounds":{"left":0.030917553,"top":0.43814844,"width":0.005319149,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.10605053,"top":0.43814844,"width":0.004654255,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.022273935,"top":0.45490822,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"mcp-server","depth":27,"bounds":{"left":0.028590426,"top":0.45490822,"width":0.023271276,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.028590426,"top":0.4557063,"width":0.003656915,"height":0.011971269}},{"char_start":1,"char_count":9,"bounds":{"left":0.032247342,"top":0.4557063,"width":0.019946808,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.021276595,"top":0.4708699,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":".env","depth":27,"bounds":{"left":0.028590426,"top":0.47246608,"width":0.00831117,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.028590426,"top":0.47326416,"width":0.0013297872,"height":0.011971269}},{"char_start":1,"char_count":3,"bounds":{"left":0.029920213,"top":0.47326416,"width":0.006981383,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.021276595,"top":0.4884278,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":".env.example","depth":27,"bounds":{"left":0.028590426,"top":0.49002394,"width":0.025930852,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.028590426,"top":0.49082202,"width":0.0013297872,"height":0.011971269}},{"char_start":1,"char_count":11,"bounds":{"left":0.029920213,"top":0.49082202,"width":0.024933511,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.021276595,"top":0.5059856,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":".gitignore","depth":27,"bounds":{"left":0.028590426,"top":0.50758183,"width":0.018949468,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.028590426,"top":0.5083799,"width":0.0013297872,"height":0.011971269}},{"char_start":1,"char_count":9,"bounds":{"left":0.029920213,"top":0.5083799,"width":0.017952127,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.021276595,"top":0.5235435,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":".mcp.json","depth":27,"bounds":{"left":0.028590426,"top":0.5251397,"width":0.019614361,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.028590426,"top":0.52593774,"width":0.0013297872,"height":0.011971269}},{"char_start":1,"char_count":8,"bounds":{"left":0.029920213,"top":0.52593774,"width":0.018284574,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"M","depth":27,"bounds":{"left":0.10638298,"top":0.52593774,"width":0.003656915,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.021276595,"top":0.54110134,"width":0.0076462766,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"alembic.ini","depth":27,"bounds":{"left":0.028590426,"top":0.54269755,"width":0.021609042,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.028590426,"top":0.5434956,"width":0.0023271276,"height":0.011971269}},{"char_start":1,"char_count":10,"bounds":{"left":0.030917553,"top":0.5434956,"width":0.019281914,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.021276595,"top":0.5586592,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"docker-compose.yml","depth":27,"bounds":{"left":0.028590426,"top":0.5602554,"width":0.042220745,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.028590426,"top":0.56105345,"width":0.0026595744,"height":0.011971269}},{"char_start":1,"char_count":17,"bounds":{"left":0.03125,"top":0.56105345,"width":0.03956117,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"M","depth":27,"bounds":{"left":0.10638298,"top":0.56105345,"width":0.003656915,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.021276595,"top":0.57621706,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Dockerfile","depth":27,"bounds":{"left":0.028590426,"top":0.57781327,"width":0.020611702,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.028590426,"top":0.5786113,"width":0.0033244682,"height":0.011971269}},{"char_start":1,"char_count":9,"bounds":{"left":0.031914894,"top":0.5786113,"width":0.017287234,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.021276595,"top":0.5937749,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"README.md","depth":27,"bounds":{"left":0.028590426,"top":0.5953711,"width":0.025265958,"height":0.011971269},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"M","depth":27,"bounds":{"left":0.10638298,"top":0.5961692,"width":0.003656915,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.021276595,"top":0.6113328,"width":0.0076462766,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"requirements.txt","depth":27,"bounds":{"left":0.028590426,"top":0.612929,"width":0.032912236,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.028590426,"top":0.61372703,"width":0.0016622341,"height":0.011971269}},{"char_start":1,"char_count":15,"bounds":{"left":0.03025266,"top":0.61372703,"width":0.03158245,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"M","depth":27,"bounds":{"left":0.10638298,"top":0.61372703,"width":0.003656915,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.021276595,"top":0.62889063,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"today_map.html","depth":27,"bounds":{"left":0.028590426,"top":0.63048685,"width":0.032247342,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.028590426,"top":0.6312849,"width":0.0016622341,"height":0.011971269}},{"char_start":1,"char_count":13,"bounds":{"left":0.03025266,"top":0.6312849,"width":0.030585106,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.6480447,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"mariadb","depth":27,"bounds":{"left":0.025930852,"top":0.6480447,"width":0.016289894,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.64884275,"width":0.003656915,"height":0.011971269}},{"char_start":1,"char_count":6,"bounds":{"left":0.029587766,"top":0.64884275,"width":0.012965426,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.66560256,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"meeting-detector","depth":27,"bounds":{"left":0.025930852,"top":0.66560256,"width":0.03557181,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.6664006,"width":0.003656915,"height":0.011971269}},{"char_start":1,"char_count":15,"bounds":{"left":0.029587766,"top":0.6664006,"width":0.031914894,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.6831604,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"mindfulmama","depth":27,"bounds":{"left":0.025930852,"top":0.6831604,"width":0.027260639,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.6839585,"width":0.003656915,"height":0.011971269}},{"char_start":1,"char_count":10,"bounds":{"left":0.029587766,"top":0.6839585,"width":0.023603724,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.7007183,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"n8n","depth":27,"bounds":{"left":0.025930852,"top":0.7007183,"width":0.0076462766,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.7015164,"width":0.0026595744,"height":0.011971269}},{"char_start":1,"char_count":2,"bounds":{"left":0.028590426,"top":0.7015164,"width":0.004986702,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.71827614,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"notifier-app","depth":27,"bounds":{"left":0.025930852,"top":0.71827614,"width":0.023603724,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.71907425,"width":0.0026595744,"height":0.011971269}},{"char_start":1,"char_count":11,"bounds":{"left":0.028590426,"top":0.71907425,"width":0.020944148,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.735834,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"npm","depth":27,"bounds":{"left":0.025930852,"top":0.735834,"width":0.008976064,"height":0.011971269},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.75339186,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"oauth","depth":27,"bounds":{"left":0.025930852,"top":0.75339186,"width":0.011303191,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.75418997,"width":0.0026595744,"height":0.011971269}},{"char_start":1,"char_count":4,"bounds":{"left":0.028590426,"top":0.75418997,"width":0.008976064,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.7709497,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"obsidian","depth":27,"bounds":{"left":0.025930852,"top":0.7709497,"width":0.016954787,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.7717478,"width":0.0026595744,"height":0.011971269}},{"char_start":1,"char_count":7,"bounds":{"left":0.028590426,"top":0.7717478,"width":0.014295213,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.7885076,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ollama","depth":27,"bounds":{"left":0.025930852,"top":0.7885076,"width":0.012965426,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.7893057,"width":0.0026595744,"height":0.011971269}},{"char_start":1,"char_count":5,"bounds":{"left":0.028590426,"top":0.7893057,"width":0.010638298,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.80606544,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"open-webui","depth":27,"bounds":{"left":0.025930852,"top":0.80606544,"width":0.023936171,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.80686355,"width":0.0026595744,"height":0.011971269}},{"char_start":1,"char_count":9,"bounds":{"left":0.028590426,"top":0.80686355,"width":0.021276595,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.8236233,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"openttd","depth":27,"bounds":{"left":0.025930852,"top":0.8236233,"width":0.015625,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.8244214,"width":0.0026595744,"height":0.011971269}},{"char_start":1,"char_count":6,"bounds":{"left":0.028590426,"top":0.8244214,"width":0.013297873,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.84118116,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"openvpn-client","depth":27,"bounds":{"left":0.025930852,"top":0.84118116,"width":0.030585106,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.84197927,"width":0.0026595744,"height":0.011971269}},{"char_start":1,"char_count":13,"bounds":{"left":0.028590426,"top":0.84197927,"width":0.027925532,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.858739,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"orchestrator","depth":27,"bounds":{"left":0.025930852,"top":0.858739,"width":0.024933511,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.8595371,"width":0.0026595744,"height":0.011971269}},{"char_start":1,"char_count":11,"bounds":{"left":0.028590426,"top":0.8595371,"width":0.022273935,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.8762969,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"outfit-app","depth":27,"bounds":{"left":0.025930852,"top":0.8762969,"width":0.020279255,"height":0.011971269},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.89385474,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"owntracks-stack","depth":27,"bounds":{"left":0.025930852,"top":0.89385474,"width":0.03357713,"height":0.011971269},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.9114126,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"paperlessngx","depth":27,"bounds":{"left":0.025930852,"top":0.9114126,"width":0.026928192,"height":0.011971269},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.92897046,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"payments-logger","depth":27,"bounds":{"left":0.025930852,"top":0.92897046,"width":0.034574468,"height":0.011971269},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.022273935,"top":0.9465283,"width":0.005319149,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":".claude","depth":27,"bounds":{"left":0.028590426,"top":0.9465283,"width":0.01462766,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Outline Section","depth":21,"bounds":{"left":0.015957447,"top":0.9473264,"width":0.09940159,"height":0.017557861},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.01662234,"top":0.9497207,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXHeading","text":"OUTLINE","depth":22,"bounds":{"left":0.022606382,"top":0.9473264,"width":0.01662234,"height":0.017557861},"on_screen":true,"role_description":"heading"},{"role":"AXStaticText","text":"OUTLINE","depth":23,"bounds":{"left":0.022606382,"top":0.95131683,"width":0.01662234,"height":0.0103751},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Timeline Section","depth":21,"bounds":{"left":0.015957447,"top":0.9648843,"width":0.09940159,"height":0.017557861},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.01662234,"top":0.96727854,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXHeading","text":"TIMELINE","depth":22,"bounds":{"left":0.022606382,"top":0.9648843,"width":0.01761968,"height":0.017557861},"on_screen":true,"role_description":"heading"},{"role":"AXStaticText","text":"TIMELINE","depth":23,"bounds":{"left":0.022606382,"top":0.9688747,"width":0.01761968,"height":0.0103751},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"docker-compose.yml, Editor Group 1","depth":28,"bounds":{"left":0.11569149,"top":0.047885075,"width":0.0674867,"height":0.02793296},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"","depth":29,"bounds":{"left":0.15159574,"top":0.07821229,"width":0.0056515955,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"docker-compose.yml, Editor Group 1","depth":28,"bounds":{"left":0.11569149,"top":0.0933759,"width":0.38031915,"height":0.0007980846},"on_screen":true,"role_description":"editor","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"Review payment logger au…, Editor Group 2","depth":28,"bounds":{"left":0.5578458,"top":0.047885075,"width":0.07679521,"height":0.02793296},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXButton","text":"remote SSH: nas","depth":16,"bounds":{"left":0.0006648936,"top":0.98244214,"width":0.028590426,"height":0.01755786},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":17,"bounds":{"left":0.0033244682,"top":0.9848364,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"SSH: nas","depth":17,"bounds":{"left":0.008643617,"top":0.9856345,"width":0.017952127,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"location-logger (Git)","depth":16,"bounds":{"left":0.030917553,"top":0.98244214,"width":0.03756649,"height":0.01755786},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":17,"bounds":{"left":0.031914894,"top":0.9848364,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"location-logger","depth":17,"bounds":{"left":0.03723404,"top":0.9856345,"width":0.03025266,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"location-logger (Git) - main*, Checkout Branch/Tag...","depth":16,"bounds":{"left":0.06815159,"top":0.98244214,"width":0.019614361,"height":0.01755786},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":17,"bounds":{"left":0.069148935,"top":0.9848364,"width":0.0056515955,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"main*","depth":17,"bounds":{"left":0.07446808,"top":0.9856345,"width":0.012300532,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"location-logger (Git) - Synchronize Changes","depth":16,"bounds":{"left":0.08743351,"top":0.98244214,"width":0.0076462766,"height":0.01755786},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"No Problems","depth":16,"bounds":{"left":0.09740692,"top":0.98244214,"width":0.022606382,"height":0.01755786},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":17,"bounds":{"left":0.09906915,"top":0.9848364,"width":0.0056515955,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"0","depth":17,"bounds":{"left":0.1043883,"top":0.9856345,"width":0.004986702,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":17,"bounds":{"left":0.109042555,"top":0.9848364,"width":0.0056515955,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"0","depth":17,"bounds":{"left":0.1143617,"top":0.9856345,"width":0.0039893617,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"No Ports Forwarded","depth":16,"bounds":{"left":0.12167553,"top":0.98244214,"width":0.012632979,"height":0.01755786},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":17,"bounds":{"left":0.12333777,"top":0.9848364,"width":0.0056515955,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"0","depth":17,"bounds":{"left":0.12865691,"top":0.9856345,"width":0.0039893617,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Notifications","depth":16,"bounds":{"left":0.9886968,"top":0.98244214,"width":0.010638298,"height":0.01755786},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sign In","depth":16,"bounds":{"left":0.9650931,"top":0.98244214,"width":0.022606382,"height":0.01755786},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":17,"bounds":{"left":0.96675533,"top":0.9848364,"width":0.0056515955,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Sign In","depth":17,"bounds":{"left":0.97207445,"top":0.9856345,"width":0.013962766,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"collapsed","depth":12,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Clear","depth":12,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Review payment logger authorization implementation","depth":19,"bounds":{"left":0.56017286,"top":0.08060654,"width":0.099734046,"height":0.022346368},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Session history","depth":19,"bounds":{"left":0.9780585,"top":0.08060654,"width":0.00930851,"height":0.022346368},"on_screen":true,"help_text":"Session history","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New session","depth":19,"bounds":{"left":0.9886968,"top":0.08060654,"width":0.00930851,"height":0.022346368},"on_screen":true,"help_text":"New session","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Message actions","depth":24,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"review payment_logger project how toes authorization work","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":23,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Thinking","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Let me explore the payment_logger project structure first.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Find payment_logger project files","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"find /volume2/docker -type f -name \"*.py\" -o -name \"*.yml\" -o -name \"*.yaml\" -o -name \"*.env\" -o -name \"*.toml\" -o -name \"*.cfg\" | grep -i payment | head -50","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"bfs: error: /volume2/docker/portnotedb/pg_commit_ts: Permission denied.\nbfs: error: /volume2/docker/portnotedb/pg_dynshmem: Permission denied.\nbfs: error: /volume2/docker/portnotedb/pg_notify: Permission denied.\nbfs: error: /volume2/docker/portnotedb/pg_serial: Permission denied.\nbfs: error: /volume2/docker/portnotedb/pg_snapshots: Permission denied.\nbfs: error: /volume2/docker/portnotedb/pg_subtrans: Permission denied.\nbfs: error: /volume2/docker/portnotedb/pg_twophase: Permission denied.\nbfs: error: /volume2/docker/portnotedb/pg_multixact: Permission denied.\nbfs: error: /volume2/docker/portnotedb/base: Permission denied.\nbfs: error: /volume2/docker/portnotedb/pg_replslot: Permission denied.\nbfs: error: /volume2/docker/portnotedb/pg_tblspc: Permission denied.\nbfs: error: /volume2/docker/portnotedb/pg_stat: Permission denied.\nbfs: error: /volume2/docker/portnotedb/pg_stat_tmp: Permission denied.\nbfs: error: /volume2/docker/portnotedb/pg_xact: Permission denied.\nbfs: error: /volume2/docker/portnotedb/pg_logical: Permission denied.\nbfs: error: /volume2/docker/openttd/.dbus: Permission denied.\nbfs: error: /volume2/docker/immich/db: Permission denied.\nbfs: error: /volume2/docker/paperlessngx/db: Permission denied.\nbfs: error: /volume2/docker/appflowy/postgres: Permission denied.\nbfs: error: /volume2/docker/auth/db: Permission denied.\nbfs: error: /volume2/docker/openttd/.XDG/dbus-1: Permission denied.\nbfs: error: /volume2/docker/openttd/.config/pulse: Permission denied.\nbfs: error: /volume2/docker/openttd/.cache/openbox/sessions: Permission denied.\n/volume2/docker/payments-logger/.env\n/volume2/docker/payments-logger/docker-compose.yml\n/volume2/docker/payments-logger/backend/prisma/migrations/migration_lock.toml","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"List docker directory contents","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ls /volume2/docker/","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"adguard\nai-stack\napp-db\nappflowy\naudiobookshelf\nauth\nbeszel\nbitwarden\ndawarich\ndsk-uploader\nflask-app\ngarmin-connector\ngitea\nhealth\nhealth-tracker\nhomarr\nhst\nimmich\njellyfinht\nkavita\nlibreoffice\nlinkwarden\nlocation-logger\nmariadb\nmeeting-detector\nmindfulmama\nn8n\nnotifier-app\nnpm\noauth\nobsidian\nollama\nopenttd\nopenvpn-client\nopen-webui\norchestrator\noutfit-app\nowntracks-stack\npaperlessngx\npayments-logger\npersonal-log\npersonal-log-system\nplayer\nportainer\nportnotedb\nreminders-app\nromm\nsecond-brain\nstatic\nstirling\nsyncthing\ntailscale\ntemp-logger\ntest-app\ntmp\ntorrent-stack\ntree\ntrilium\ntubearchivist\ntwenty\nuptimekuma\nytptube","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Agent:","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Explore payment_logger authorization code","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Explore the payments-logger project at /volume2/docker/payments-logger and give me a thorough understanding of how authorization works. I need to know:\n\n1. What auth mechanism is used (JWT, sessions, API keys, OAuth, etc.)\n2. Where auth is enforced (middleware, decorators, route guards, etc.)\n3. What roles/permissions exist\n4. How tokens are issued, validated, and refreshed\n5. Any auth-related config (env vars, settings)\n\nPlease read the key source files and give me a clear summary with file paths and line numbers for the important parts.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"find /volume2/docker/payments-logger -type f -name \"*.py\" -o -name \"*.json\" -o -name \"*.yml\" -o -name \"*.yaml\" | grep -E \"(auth|token|jwt|session|permission|role)\" | head -20","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"(Bash completed with no output)","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ls -la /volume2/docker/payments-logger/ 2>/dev/null || echo \"Directory not found\"","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"total 36\ndrwxrwxrwx 1 Adm1n admin 162 Mar 29 18:01 .\ndrwxrwxrwx 1 root root 1146 Apr 26 18:49 ..\n-rwxrwxrwx 1 Adm1n admin 15233 Feb 22 17:08 API.md\ndrwxrwxrwx 1 Adm1n admin 88 Mar 29 15:41 backend\ndrwxrwxrwx 1 Adm1n admin 38 Mar 29 17:07 .claude\n-rwxrwxrwx 1 Adm1n admin 1502 Mar 29 18:01 docker-compose.yml\n-rwxrwxrwx 1 Adm1n admin 1066 Mar 29 15:44 .env\n-rwxrwxrwx 1 Adm1n admin 1078 Feb 14 17:53 .env.example\ndrwxrwxrwx 1 Adm1n admin 194 Mar 29 15:44 frontend\n-rwxrwxrwx 1 Adm1n admin 19 Feb 14 17:54 .gitignore\n-rwxrwxrwx 1 Adm1n admin 4052 Feb 14 19:06 README.md","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"find /volume2/docker/payments-logger/backend -type f | head -30","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/volume2/docker/payments-logger/backend/Dockerfile\n/volume2/docker/payments-logger/backend/.dockerignore\n/volume2/docker/payments-logger/backend/package.json\n/volume2/docker/payments-logger/backend/prisma/schema.prisma\n/volume2/docker/payments-logger/backend/src/parser.js\n/volume2/docker/payments-logger/backend/src/index.js\n/volume2/docker/payments-logger/backend/src/auth.js\n/volume2/docker/payments-logger/backend/prisma/migrations/migration_lock.toml\n/volume2/docker/payments-logger/backend/src/routes/payments.js\n/volume2/docker/payments-logger/backend/prisma/migrations/20260210_init/migration.sql\n/volume2/docker/payments-logger/backend/prisma/migrations/20260210_simplify/migration.sql\n/volume2/docker/payments-logger/backend/prisma/migrations/20260222_add_card/migration.sql","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"find /volume2/docker/payments-logger -type f \\( -name \"*.js\" -o -name \"*.json\" -o -name \"*.md\" \\) | sort","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/volume2/docker/payments-logger/API.md\n/volume2/docker/payments-logger/backend/package.json\n/volume2/docker/payments-logger/backend/src/auth.js\n/volume2/docker/payments-logger/backend/src/index.js\n/volume2/docker/payments-logger/backend/src/parser.js\n/volume2/docker/payments-logger/backend/src/routes/payments.js\n/volume2/docker/payments-logger/.claude/settings.local.json\n/volume2/docker/payments-logger/frontend/package.json\n/volume2/docker/payments-logger/frontend/postcss.config.js\n/volume2/docker/payments-logger/frontend/src/auth.js\n/volume2/docker/payments-logger/frontend/tailwind.config.js\n/volume2/docker/payments-logger/frontend/vite.config.js\n/volume2/docker/payments-logger/README.md","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":".env","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":".env","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"auth.js","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"auth.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"index.js","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"index.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"package.json","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"package.json","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"auth.js","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"auth.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"API.md","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"API.md","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"payments.js","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"payments.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":".env.example","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":".env.example","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"schema.prisma","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"schema.prisma","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"grep -r \"API_KEY\\|auth\\|token\\|oauth\\|hydra\" /volume2/docker/payments-logger/backend/src --include=\"*.js\" -n","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/volume2/docker/payments-logger/backend/src/index.js:6:const { bearerTokenMiddleware, wellKnownRouter } = require('./auth');\n/volume2/docker/payments-logger/backend/src/index.js:18:// ── OAuth Bearer token auth (skips public paths) ──────────────────────────────\n/volume2/docker/payments-logger/backend/src/auth.js:2: * OAuth 2.1 / Hydra JWT authentication for Express.\n/volume2/docker/payments-logger/backend/src/auth.js:6: * - wellKnownRouter — serves /.well-known/oauth-* discovery endpoints\n/volume2/docker/payments-logger/backend/src/auth.js:33:function sendUnauthorized(res, detail, error = 'invalid_token') {\n/volume2/docker/payments-logger/backend/src/auth.js:39: `resource_metadata=\"${realm}/.well-known/oauth-protected-resource\"`,\n/volume2/docker/payments-logger/backend/src/auth.js:40: `authorization_server=\"${HYDRA_PUBLIC_URL}\"`,\n/volume2/docker/payments-logger/backend/src/auth.js:52: * On success, attaches the decoded payload to req.tokenPayload.\n/volume2/docker/payments-logger/backend/src/auth.js:54: * @param {Set<string>} publicPaths Paths to skip auth for.\n/volume2/docker/payments-logger/backend/src/auth.js:58: '/.well-known/oauth-protected-resource',\n/volume2/docker/payments-logger/backend/src/auth.js:59: '/.well-known/oauth-authorization-server',\n/volume2/docker/payments-logger/backend/src/auth.js:66: const auth = req.headers.authorization || '';\n/volume2/docker/payments-logger/backend/src/auth.js:67: if (!auth.toLowerCase().startsWith('bearer ')) {\n/volume2/docker/payments-logger/backend/src/auth.js:68: return sendUnauthorized(res, 'Bearer token required', 'invalid_request');\n/volume2/docker/payments-logger/backend/src/auth.js:71: const token = auth.slice(7).trim();\n/volume2/docker/payments-logger/backend/src/auth.js:72: if (!token) {\n/volume2/docker/payments-logger/backend/src/auth.js:73: return sendUnauthorized(res, 'Bearer token required', 'invalid_request');\n/volume2/docker/payments-logger/backend/src/auth.js:82: const { payload } = await jwtVerify(token, getJwks(), verifyOptions);\n/volume2/docker/payments-logger/backend/src/auth.js:83: req.tokenPayload = payload;\n/volume2/docker/payments-logger/backend/src/auth.js:87: const error = msg.includes('expired') ? 'invalid_token' : 'invalid_token';\n/volume2/docker/payments-logger/backend/src/auth.js:88: sendUnauthorized(res, msg, error);\n/volume2/docker/payments-logger/backend/src/auth.js:98:wellKnownRouter.get('/.well-known/oauth-protected-resource', (_req, res) => {\n/volume2/docker/payments-logger/backend/src/auth.js:103: authorization_servers: [HYDRA_PUBLIC_URL],\n/volume2/docker/payments-logger/backend/src/auth.js:111:wellKnownRouter.get('/.well-known/oauth-authorization-server', async (_req, res) => {\n/volume2/docker/payments-logger/backend/src/auth.js:119: authorization_endpoint: doc.authorization_endpoint,\n/volume2/docker/payments-logger/backend/src/auth.js:120: token_endpoint: doc.token_endpoint,\n/volume2/docker/payments-logger/backend/src/auth.js:123: grant_types_supported: doc.grant_types_supported || ['authorization_code', 'refresh_token'],\n/volume2/docker/payments-logger/backend/src/auth.js:124: token_endpoint_auth_methods_supported: doc.token_endpoint_auth_methods_supported || ['none', 'client_secret_basic'],\n/volume2/docker/payments-logger/backend/src/auth.js:128: id_token_signing_alg_values_supported: doc.id_token_signing_alg_values_supported || ['RS256'],\n/volume2/docker/payments-logger/backend/src/routes/payments.js:58:// ── Ingest a payment (public — no auth) ──────────────────────────────────────","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"find /volume2/docker/payments-logger/frontend/src -type f -name \"*.js\" -o -name \"*.jsx\" -o -name \"*.ts\" -o -name \"*.tsx\" | head -20","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/volume2/docker/payments-logger/frontend/src/main.jsx\n/volume2/docker/payments-logger/frontend/src/App.jsx\n/volume2/docker/payments-logger/frontend/src/auth.js\n/volume2/docker/payments-logger/frontend/src/components/PaymentCard.jsx\n/volume2/docker/payments-logger/frontend/src/components/PaymentList.jsx\n/volume2/docker/payments-logger/frontend/src/components/FilterBar.jsx\n/volume2/docker/payments-logger/frontend/src/components/PaymentTable.jsx\n/volume2/docker/payments-logger/frontend/src/components/AuthProvider.jsx\n/volume2/docker/payments-logger/frontend/src/components/AuthCallback.jsx","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"AuthProvider.jsx","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"AuthProvider.jsx","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"AuthCallback.jsx","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"AuthCallback.jsx","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"App.jsx","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"App.jsx","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"main.jsx","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"main.jsx","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"vite.config.js","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"vite.config.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"grep -r \"HYDRA\\|VITE\" /volume2/docker/payments-logger --include=\".env*\" -n","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"(Bash completed with no output)","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"docker-compose.yml","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"docker-compose.yml","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"grep -r \"API_KEY\" /volume2/docker/payments-logger/backend --include=\"*.js\" -n","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"(Bash completed with no output)","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"README.md","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"README.md","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"grep -n \"HYDRA\\|oauth\\|TOKEN\" /volume2/docker/payments-logger/backend/src/index.js /volume2/docker/payments-logger/backend/src/auth.js | head -40","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/volume2/docker/payments-logger/backend/src/auth.js:6: * - wellKnownRouter — serves /.well-known/oauth-* discovery endpoints\n/volume2/docker/payments-logger/backend/src/auth.js:11:const HYDRA_PUBLIC_URL = (process.env.HYDRA_PUBLIC_URL || '').replace(/\\/$/, '');\n/volume2/docker/payments-logger/backend/src/auth.js:24: new URL(`${HYDRA_PUBLIC_URL}/.well-known/jwks.json`)\n/volume2/docker/payments-logger/backend/src/auth.js:39: `resource_metadata=\"${realm}/.well-known/oauth-protected-resource\"`,\n/volume2/docker/payments-logger/backend/src/auth.js:40: `authorization_server=\"${HYDRA_PUBLIC_URL}\"`,\n/volume2/docker/payments-logger/backend/src/auth.js:58: '/.well-known/oauth-protected-resource',\n/volume2/docker/payments-logger/backend/src/auth.js:59: '/.well-known/oauth-authorization-server',\n/volume2/docker/payments-logger/backend/src/auth.js:78: issuer: HYDRA_PUBLIC_URL,\n/volume2/docker/payments-logger/backend/src/auth.js:81: if (process.env.TOKEN_AUDIENCE) verifyOptions.audience = process.env.TOKEN_AUDIENCE;\n/volume2/docker/payments-logger/backend/src/auth.js:98:wellKnownRouter.get('/.well-known/oauth-protected-resource', (_req, res) => {\n/volume2/docker/payments-logger/backend/src/auth.js:103: authorization_servers: [HYDRA_PUBLIC_URL],\n/volume2/docker/payments-logger/backend/src/auth.js:107: jwks_uri: `${HYDRA_PUBLIC_URL}/.well-known/jwks.json`,\n/volume2/docker/payments-logger/backend/src/auth.js:111:wellKnownRouter.get('/.well-known/oauth-authorization-server', async (_req, res) => {\n/volume2/docker/payments-logger/backend/src/auth.js:113: const r = await fetch(`${HYDRA_PUBLIC_URL}/.well-known/openid-configuration`);\n/volume2/docker/payments-logger/backend/src/auth.js:118: issuer: doc.issuer || HYDRA_PUBLIC_URL,","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":23,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Thinking","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"payments-logger Authorization Overview","depth":22,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"payments-logger Authorization Overview","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"The project uses","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"OAuth 2.1 with PKCE","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"via an external Hydra OAuth server at","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"hydra.lakylak.xyz","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"Auth Flow","depth":22,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"Auth Flow","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Frontend","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"(","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"frontend/src/auth.js","depth":23,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"frontend/src/auth.js","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"):","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Fetches OAuth server metadata via discovery endpoint","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Generates a PKCE code verifier/challenge (SHA-256)","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Redirects user to Hydra login with","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"code_challenge","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"On callback, exchanges code + verifier for tokens","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Stores","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"access_token","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":",","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"refresh_token","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"in","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"localStorage","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"(","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"pl_oauth_tokens","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":")","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Auto-refreshes token 30 seconds before expiry","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Backend","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"(","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"backend/src/auth.js","depth":23,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"backend/src/auth.js","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"):","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"bearerTokenMiddleware","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"validates the","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Authorization: Bearer <token>","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"header","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Fetches Hydra's JWKS (cached 300s) and verifies JWT signature (RS256/ES256/PS256)","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Validates issuer (","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"https://hydra.lakylak.xyz","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":") and optional audience","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"Enforcement","depth":22,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"Enforcement","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Applied globally in","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"backend/src/index.js:19","depth":23,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"backend/src/index.js:19","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"with these","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"public (unprotected) paths","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":":","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/.well-known/oauth-protected-resource","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/.well-known/oauth-authorization-server","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/api/health","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/api/payments/ingest","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"(rate-limited at 200 req/min — for SMS ingestion)","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"Roles/Permissions","depth":22,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"Roles/Permissions","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"No RBAC","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"— it's binary: authenticated vs. unauthenticated. Required scopes:","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"openid","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":",","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"offline_access","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"Key Security Notes","depth":22,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"Key Security Notes","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PKCE","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"prevents authorization code interception","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"State parameter","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"provides CSRF protection","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"No server-side token storage","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"— validation is stateless via JWKS","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"The README/API docs mention an","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"X-API-Key","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"header, but that's","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"outdated","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"— the actual code uses Bearer tokens only","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Config lives in","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"docker-compose.yml","depth":23,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"docker-compose.yml","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"(lines 30–33):","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"HYDRA_PUBLIC_URL","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":",","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"REQUIRED_SCOPES","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":",","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"OAUTH_CLIENT_ID","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":", and optionally","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"TOKEN_AUDIENCE","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"JWKS_CACHE_TTL","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Message actions","depth":24,"bounds":{"left":0.9900266,"top":0.11173184,"width":0.0066489363,"height":0.015961692},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"compare it to location logger and make it the same. Lets remove hydra and only use authentic (or whatever location logger uses).","depth":25,"bounds":{"left":0.5671542,"top":0.12529927,"width":0.25930852,"height":0.011971269},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":23,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Thinking","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Let me first explore how location-logger handles authorization.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Agent:","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Explore location-logger authorization code","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Explore the location-logger project at /volume2/docker/location-logger and give me a thorough understanding of how authorization works. I need to know:\n\n1. What auth mechanism is used (JWT, sessions, API keys, OAuth, etc.)\n2. Where auth is enforced (middleware, decorators, route guards, etc.)\n3. What roles/permissions exist\n4. How tokens are issued, validated, and refreshed\n5. Any auth-related config (env vars, settings)\n6. Frontend auth flow (how the user logs in, how tokens are stored and used)\n7. The full directory/file structure of the project\n\nPlease read ALL relevant source files completely and give me a detailed summary with file paths and line numbers. I need enough detail to replicate this auth system in another project.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"find /volume2/docker/location-logger -type f -name \"*.py\" -o -name \"*.js\" -o -name \"*.ts\" -o -name \"*.json\" | head -50","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/volume2/docker/location-logger/.mcp.json\n/volume2/docker/location-logger/app/__init__.py\n/volume2/docker/location-logger/app/utils.py\n/volume2/docker/location-logger/app/config.py\n/volume2/docker/location-logger/app/main.py\n/volume2/docker/location-logger/alembic/env.py\n/volume2/docker/location-logger/mcp-server/server.py\n/volume2/docker/location-logger/alembic/versions/20260203_201500_create_location_points_table.py\n/volume2/docker/location-logger/alembic/versions/20260209_200000_add_enhanced_fields_and_tables.py\n/volume2/docker/location-logger/alembic/versions/20260214_000000_add_users_and_audit_logs.py\n/volume2/docker/location-logger/alembic/versions/20260320_000000_add_audit_query_string.py\n/volume2/docker/location-logger/app/services/geofence_service.py\n/volume2/docker/location-logger/app/services/recorder_service.py\n/volume2/docker/location-logger/app/services/trip_service.py\n/volume2/docker/location-logger/app/services/enhanced_location_service.py\n/volume2/docker/location-logger/app/services/geocoding_service.py\n/volume2/docker/location-logger/app/clients/__init__.py\n/volume2/docker/location-logger/app/clients/dawarich_client.py\n/volume2/docker/location-logger/app/clients/owntracks_client.py\n/volume2/docker/location-logger/app/models/areas.py\n/volume2/docker/location-logger/app/models/geofence_events.py\n/volume2/docker/location-logger/app/models/trips.py\n/volume2/docker/location-logger/app/models/user.py\n/volume2/docker/location-logger/app/models/location.py\n/volume2/docker/location-logger/app/models/audit_log.py\n/volume2/docker/location-logger/app/auth/__init__.py\n/volume2/docker/location-logger/app/auth/dependencies.py\n/volume2/docker/location-logger/app/auth/utils.py\n/volume2/docker/location-logger/app/api/enhanced_endpoints.py\n/volume2/docker/location-logger/app/db/base.py\n/volume2/docker/location-logger/app/db/session.py","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"tree -L 4 /volume2/docker/location-logger 2>/dev/null || find /volume2/docker/location-logger -type d | sort","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/volume2/docker/location-logger\n├── alembic\n│ ├── env.py\n│ ├── script.py.mako\n│ └── versions\n│ ├── 20260203_201500_create_location_points_table.py\n│ ├── 20260209_200000_add_enhanced_fields_and_tables.py\n│ ├── 20260214_000000_add_users_and_audit_logs.py\n│ ├── 20260320_000000_add_audit_query_string.py\n│ └── __pycache__\n│ └── 20260214_000000_add_users_and_audit_logs.cpython-311.pyc\n├── alembic.ini\n├── app\n│ ├── api\n│ │ └── enhanced_endpoints.py\n│ ├── auth\n│ │ ├── dependencies.py\n│ │ ├── __init__.py\n│ │ ├── __pycache__\n│ │ │ ├── dependencies.cpython-311.pyc\n│ │ │ ├── __init__.cpython-311.pyc\n│ │ │ └── utils.cpython-311.pyc\n│ │ └── utils.py\n│ ├── clients\n│ │ ├── dawarich_client.py\n│ │ ├── __init__.py\n│ │ └── owntracks_client.py\n│ ├── config.py\n│ ├── db\n│ │ ├── base.py\n│ │ └── session.py\n│ ├── __init__.py\n│ ├── main.py\n│ ├── models\n│ │ ├── areas.py\n│ │ ├── audit_log.py\n│ │ ├── geofence_events.py\n│ │ ├── location.py\n│ │ ├── __pycache__\n│ │ │ ├── audit_log.cpython-311.pyc\n│ │ │ └── user.cpython-311.pyc\n│ │ ├── trips.py\n│ │ └── user.py\n│ ├── __pycache__\n│ │ ├── __init__.cpython-311.pyc\n│ │ └── main.cpython-311.pyc\n│ ├── services\n│ │ ├── enhanced_location_service.py\n│ │ ├── geocoding_service.py\n│ │ ├── geofence_service.py\n│ │ ├── recorder_service.py\n│ │ └── trip_service.py\n│ ├── static\n│ │ └── dashboard.html\n│ └── utils.py\n├── docker-compose.yml\n├── Dockerfile\n├── mcp-server\n│ ├── Dockerfile\n│ ├── requirements.txt\n│ └── server.py\n├── README.md\n├── requirements.txt\n└── today_map.html\n\n16 directories, 48 files","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"utils.py","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"utils.py","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"dependencies.py","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"dependencies.py","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"user.py","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"user.py","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"config.py","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"config.py","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"main.py","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"main.py","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"session.py","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"session.py","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"dashboard.html","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"dashboard.html","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"audit_log.py","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"audit_log.py","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"20260214_000000_add_users_and_audit_logs.py","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"20260214_000000_add_users_and_audit_logs.py","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"20260320_000000_add_audit_query_string.py","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"20260320_000000_add_audit_query_string.py","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"README.md","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"README.md","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"requirements.txt","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"requirements.txt","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"server.py","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"server.py","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"server.py","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"server.py","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"(lines 101-400)","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":23,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Thinking","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Now I have a full picture of both systems. Let me read the payments-logger source files before planning the migration.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"List all payments-logger files","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"find /volume2/docker/payments-logger -type f | grep -v node_modules | grep -v .git | sort","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/volume2/docker/payments-logger/API.md\n/volume2/docker/payments-logger/backend/Dockerfile\n/volume2/docker/payments-logger/backend/.dockerignore\n/volume2/docker/payments-logger/backend/package.json\n/volume2/docker/payments-logger/backend/prisma/migrations/20260210_init/migration.sql\n/volume2/docker/payments-logger/backend/prisma/migrations/20260210_simplify/migration.sql\n/volume2/docker/payments-logger/backend/prisma/migrations/20260222_add_card/migration.sql\n/volume2/docker/payments-logger/backend/prisma/migrations/migration_lock.toml\n/volume2/docker/payments-logger/backend/prisma/schema.prisma\n/volume2/docker/payments-logger/backend/src/auth.js\n/volume2/docker/payments-logger/backend/src/index.js\n/volume2/docker/payments-logger/backend/src/parser.js\n/volume2/docker/payments-logger/backend/src/routes/payments.js\n/volume2/docker/payments-logger/.claude/settings.local.json\n/volume2/docker/payments-logger/docker-compose.yml\n/volume2/docker/payments-logger/.env\n/volume2/docker/payments-logger/.env.example\n/volume2/docker/payments-logger/frontend/Dockerfile\n/volume2/docker/payments-logger/frontend/.dockerignore\n/volume2/docker/payments-logger/frontend/index.html\n/volume2/docker/payments-logger/frontend/package.json\n/volume2/docker/payments-logger/frontend/postcss.config.js\n/volume2/docker/payments-logger/frontend/src/App.jsx\n/volume2/docker/payments-logger/frontend/src/auth.js\n/volume2/docker/payments-logger/frontend/src/components/AuthCallback.jsx\n/volume2/docker/payments-logger/frontend/src/components/AuthProvider.jsx\n/volume2/docker/payments-logger/frontend/src/components/FilterBar.jsx\n/volume2/docker/payments-logger/frontend/src/components/PaymentCard.jsx\n/volume2/docker/payments-logger/frontend/src/components/PaymentList.jsx\n/volume2/docker/payments-logger/frontend/src/components/PaymentTable.jsx\n/volume2/docker/payments-logger/frontend/src/index.css\n/volume2/docker/payments-logger/frontend/src/main.jsx\n/volume2/docker/payments-logger/frontend/tailwind.config.js\n/volume2/docker/payments-logger/frontend/vite.config.js\n/volume2/docker/payments-logger/README.md","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"auth.js","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"auth.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"index.js","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"index.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"auth.js","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"auth.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"AuthProvider.jsx","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"AuthProvider.jsx","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"package.json","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"package.json","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"AuthCallback.jsx","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"AuthCallback.jsx","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"schema.prisma","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"schema.prisma","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"docker-compose.yml","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"docker-compose.yml","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":23,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Thinking","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Now let me read the remaining frontend files.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"App.jsx","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"App.jsx","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"package.json","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"package.json","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":".env","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":".env","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":23,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Thinking","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Let me read the remaining files before making changes.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"main.jsx","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"main.jsx","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"vite.config.js","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"vite.config.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"payments.js","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"payments.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":23,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Thinking","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":".env.example","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":".env.example","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":23,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Thinking","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Now I have everything I need. Here's what changes:","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Backend:","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Rewrite","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"auth.js","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"(HS256 JWT + bcrypt), add","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/auth/login","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"+","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/auth/register","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"endpoints, add","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"User","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"model to Prisma, new migration, remove Hydra env vars.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Frontend:","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Replace PKCE flow with a simple login form in","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AuthProvider","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":", simplify","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"auth.js","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":", remove","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AuthCallback","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":", drop","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/.well-known","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"proxy.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Config:","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Drop all Hydra/OAuth env vars, add","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"JWT_SECRET","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Let me implement everything now.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Update Todos","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Add bcryptjs to backend package.json","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Rewrite backend/src/auth.js (HS256 JWT + bcrypt, login/register routes)","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Update backend/src/index.js (remove wellKnownRouter, mount authRouter)","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Add User model to prisma/schema.prisma","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Create Prisma migration for users table","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Rewrite frontend/src/auth.js (simple username/password login)","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Rewrite frontend/src/components/AuthProvider.jsx (login form instead of PKCE redirect)","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Update frontend/src/main.jsx (remove /auth/callback handling)","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Delete frontend/src/components/AuthCallback.jsx","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Update frontend/vite.config.js (remove /.well-known proxy)","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Update docker-compose.yml (remove Hydra vars/network, add JWT_SECRET)","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Update .env and .env.example","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Update Todos","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Add bcryptjs to backend package.json","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Rewrite backend/src/auth.js (HS256 JWT + bcrypt, login/register routes)","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Update backend/src/index.js (remove wellKnownRouter, mount authRouter)","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Add User model to prisma/schema.prisma","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Create Prisma migration for users table","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Rewrite frontend/src/auth.js (simple username/password login)","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Rewrite frontend/src/components/AuthProvider.jsx (login form instead of PKCE redirect)","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Update frontend/src/main.jsx (remove /auth/callback handling)","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Delete frontend/src/components/AuthCallback.jsx","depth":26,"on_screen":false,"role_description":"text"}]...
|
-947440867846459287
|
-4844822280039181748
|
click
|
accessibility
|
NULL
|
Explorer (⇧⌘E)
Search (⇧⌘F)
Source Control (⌃⇧ Explorer (⇧⌘E)
Search (⇧⌘F)
Source Control (⌃⇧G) - 55 pending changes
55
Run and Debug (⇧⌘D)
Remote Explorer
Extensions (⇧⌘X) - 2 require update
2
Claude Code
Containers
EXPLORER
EXPLORER
Explorer Section: docker [SSH: nas]
Explorer Section: docker [SSH: nas]
DOCKER [SSH: NAS]
audiobookshelf
auth
beszel
bitwarden
dawarich
dsk-uploader
flask-app
garmin-connector
gitea
health
health-tracker
homarr
hst
immich
jellyfinht
kavita
libreoffice
linkwarden
location-logger
alembic
app
mcp-server
.env
.env.example
.gitignore
.mcp.json
M
alembic.ini
docker-compose.yml
M
Dockerfile
README.md
M
requirements.txt
M
today_map.html
mariadb
meeting-detector
mindfulmama
n8n
notifier-app
npm
oauth
obsidian
ollama
open-webui
openttd
openvpn-client
orchestrator
outfit-app
owntracks-stack
paperlessngx
payments-logger
.claude
Outline Section
OUTLINE
OUTLINE
Timeline Section
TIMELINE
TIMELINE
docker-compose.yml, Editor Group 1
docker-compose.yml, Editor Group 1
Review payment logger au…, Editor Group 2
remote SSH: nas
SSH: nas
location-logger (Git)
location-logger
location-logger (Git) - main*, Checkout Branch/Tag...
main*
location-logger (Git) - Synchronize Changes
No Problems
0
0
No Ports Forwarded
0
Notifications
Sign In
Sign In
collapsed
Clear
Review payment logger authorization implementation
Session history
New session
Message actions
review payment_logger project how toes authorization work
Thinking
Thinking
Let me explore the payment_logger project structure first.
Bash
Find payment_logger project files
IN
find /volume2/docker -type f -name "*.py" -o -name "*.yml" -o -name "*.yaml" -o -name "*.env" -o -name "*.toml" -o -name "*.cfg" | grep -i payment | head -50
Copy code to clipboard
OUT
bfs: error: /volume2/docker/portnotedb/pg_commit_ts: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_dynshmem: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_notify: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_serial: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_snapshots: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_subtrans: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_twophase: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_multixact: Permission denied.
bfs: error: /volume2/docker/portnotedb/base: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_replslot: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_tblspc: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_stat: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_stat_tmp: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_xact: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_logical: Permission denied.
bfs: error: /volume2/docker/openttd/.dbus: Permission denied.
bfs: error: /volume2/docker/immich/db: Permission denied.
bfs: error: /volume2/docker/paperlessngx/db: Permission denied.
bfs: error: /volume2/docker/appflowy/postgres: Permission denied.
bfs: error: /volume2/docker/auth/db: Permission denied.
bfs: error: /volume2/docker/openttd/.XDG/dbus-1: Permission denied.
bfs: error: /volume2/docker/openttd/.config/pulse: Permission denied.
bfs: error: /volume2/docker/openttd/.cache/openbox/sessions: Permission denied.
/volume2/docker/payments-logger/.env
/volume2/docker/payments-logger/docker-compose.yml
/volume2/docker/payments-logger/backend/prisma/migrations/migration_lock.toml
Bash
List docker directory contents
IN
ls /volume2/docker/
Copy code to clipboard
OUT
adguard
ai-stack
app-db
appflowy
audiobookshelf
auth
beszel
bitwarden
dawarich
dsk-uploader
flask-app
garmin-connector
gitea
health
health-tracker
homarr
hst
immich
jellyfinht
kavita
libreoffice
linkwarden
location-logger
mariadb
meeting-detector
mindfulmama
n8n
notifier-app
npm
oauth
obsidian
ollama
openttd
openvpn-client
open-webui
orchestrator
outfit-app
owntracks-stack
paperlessngx
payments-logger
personal-log
personal-log-system
player
portainer
portnotedb
reminders-app
romm
second-brain
static
stirling
syncthing
tailscale
temp-logger
test-app
tmp
torrent-stack
tree
trilium
tubearchivist
twenty
uptimekuma
ytptube
Agent:
Explore payment_logger authorization code
IN
Explore the payments-logger project at /volume2/docker/payments-logger and give me a thorough understanding of how authorization works. I need to know:
1. What auth mechanism is used (JWT, sessions, API keys, OAuth, etc.)
2. Where auth is enforced (middleware, decorators, route guards, etc.)
3. What roles/permissions exist
4. How tokens are issued, validated, and refreshed
5. Any auth-related config (env vars, settings)
Please read the key source files and give me a clear summary with file paths and line numbers for the important parts.
Bash
IN
find /volume2/docker/payments-logger -type f -name "*.py" -o -name "*.json" -o -name "*.yml" -o -name "*.yaml" | grep -E "(auth|token|jwt|session|permission|role)" | head -20
Copy code to clipboard
OUT
(Bash completed with no output)
Bash
IN
ls -la /volume2/docker/payments-logger/ 2>/dev/null || echo "Directory not found"
Copy code to clipboard
OUT
total 36
drwxrwxrwx 1 Adm1n admin 162 Mar 29 18:01 .
drwxrwxrwx 1 root root 1146 Apr 26 18:49 ..
-rwxrwxrwx 1 Adm1n admin 15233 Feb 22 17:08 API.md
drwxrwxrwx 1 Adm1n admin 88 Mar 29 15:41 backend
drwxrwxrwx 1 Adm1n admin 38 Mar 29 17:07 .claude
-rwxrwxrwx 1 Adm1n admin 1502 Mar 29 18:01 docker-compose.yml
-rwxrwxrwx 1 Adm1n admin 1066 Mar 29 15:44 .env
-rwxrwxrwx 1 Adm1n admin 1078 Feb 14 17:53 .env.example
drwxrwxrwx 1 Adm1n admin 194 Mar 29 15:44 frontend
-rwxrwxrwx 1 Adm1n admin 19 Feb 14 17:54 .gitignore
-rwxrwxrwx 1 Adm1n admin 4052 Feb 14 19:06 README.md
Bash
IN
find /volume2/docker/payments-logger/backend -type f | head -30
Copy code to clipboard
OUT
/volume2/docker/payments-logger/backend/Dockerfile
/volume2/docker/payments-logger/backend/.dockerignore
/volume2/docker/payments-logger/backend/package.json
/volume2/docker/payments-logger/backend/prisma/schema.prisma
/volume2/docker/payments-logger/backend/src/parser.js
/volume2/docker/payments-logger/backend/src/index.js
/volume2/docker/payments-logger/backend/src/auth.js
/volume2/docker/payments-logger/backend/prisma/migrations/migration_lock.toml
/volume2/docker/payments-logger/backend/src/routes/payments.js
/volume2/docker/payments-logger/backend/prisma/migrations/20260210_init/migration.sql
/volume2/docker/payments-logger/backend/prisma/migrations/20260210_simplify/migration.sql
/volume2/docker/payments-logger/backend/prisma/migrations/20260222_add_card/migration.sql
Bash
IN
find /volume2/docker/payments-logger -type f \( -name "*.js" -o -name "*.json" -o -name "*.md" \) | sort
Copy code to clipboard
OUT
/volume2/docker/payments-logger/API.md
/volume2/docker/payments-logger/backend/package.json
/volume2/docker/payments-logger/backend/src/auth.js
/volume2/docker/payments-logger/backend/src/index.js
/volume2/docker/payments-logger/backend/src/parser.js
/volume2/docker/payments-logger/backend/src/routes/payments.js
/volume2/docker/payments-logger/.claude/settings.local.json
/volume2/docker/payments-logger/frontend/package.json
/volume2/docker/payments-logger/frontend/postcss.config.js
/volume2/docker/payments-logger/frontend/src/auth.js
/volume2/docker/payments-logger/frontend/tailwind.config.js
/volume2/docker/payments-logger/frontend/vite.config.js
/volume2/docker/payments-logger/README.md
Read
.env
.env
Read
auth.js
auth.js
Read
index.js
index.js
Read
package.json
package.json
Read
auth.js
auth.js
Read
API.md
API.md
Read
payments.js
payments.js
Read
.env.example
.env.example
Read
schema.prisma
schema.prisma
Bash
IN
grep -r "API_KEY\|auth\|token\|oauth\|hydra" /volume2/docker/payments-logger/backend/src --include="*.js" -n
Copy code to clipboard
OUT
/volume2/docker/payments-logger/backend/src/index.js:6:const { bearerTokenMiddleware, wellKnownRouter } = require('./auth');
/volume2/docker/payments-logger/backend/src/index.js:18:// ── OAuth Bearer token auth (skips public paths) ──────────────────────────────
/volume2/docker/payments-logger/backend/src/auth.js:2: * OAuth 2.1 / Hydra JWT authentication for Express.
/volume2/docker/payments-logger/backend/src/auth.js:6: * - wellKnownRouter — serves /.well-known/oauth-* discovery endpoints
/volume2/docker/payments-logger/backend/src/auth.js:33:function sendUnauthorized(res, detail, error = 'invalid_token') {
/volume2/docker/payments-logger/backend/src/auth.js:39: `resource_metadata="${realm}/.well-known/oauth-protected-resource"`,
/volume2/docker/payments-logger/backend/src/auth.js:40: `authorization_server="${HYDRA_PUBLIC_URL}"`,
/volume2/docker/payments-logger/backend/src/auth.js:52: * On success, attaches the decoded payload to req.tokenPayload.
/volume2/docker/payments-logger/backend/src/auth.js:54: * @param {Set<string>} publicPaths Paths to skip auth for.
/volume2/docker/payments-logger/backend/src/auth.js:58: '/.well-known/oauth-protected-resource',
/volume2/docker/payments-logger/backend/src/auth.js:59: '/.well-known/oauth-authorization-server',
/volume2/docker/payments-logger/backend/src/auth.js:66: const auth = req.headers.authorization || '';
/volume2/docker/payments-logger/backend/src/auth.js:67: if (!auth.toLowerCase().startsWith('bearer ')) {
/volume2/docker/payments-logger/backend/src/auth.js:68: return sendUnauthorized(res, 'Bearer token required', 'invalid_request');
/volume2/docker/payments-logger/backend/src/auth.js:71: const token = auth.slice(7).trim();
/volume2/docker/payments-logger/backend/src/auth.js:72: if (!token) {
/volume2/docker/payments-logger/backend/src/auth.js:73: return sendUnauthorized(res, 'Bearer token required', 'invalid_request');
/volume2/docker/payments-logger/backend/src/auth.js:82: const { payload } = await jwtVerify(token, getJwks(), verifyOptions);
/volume2/docker/payments-logger/backend/src/auth.js:83: req.tokenPayload = payload;
/volume2/docker/payments-logger/backend/src/auth.js:87: const error = msg.includes('expired') ? 'invalid_token' : 'invalid_token';
/volume2/docker/payments-logger/backend/src/auth.js:88: sendUnauthorized(res, msg, error);
/volume2/docker/payments-logger/backend/src/auth.js:98:wellKnownRouter.get('/.well-known/oauth-protected-resource', (_req, res) => {
/volume2/docker/payments-logger/backend/src/auth.js:103: authorization_servers: [HYDRA_PUBLIC_URL],
/volume2/docker/payments-logger/backend/src/auth.js:111:wellKnownRouter.get('/.well-known/oauth-authorization-server', async (_req, res) => {
/volume2/docker/payments-logger/backend/src/auth.js:119: authorization_endpoint: doc.authorization_endpoint,
/volume2/docker/payments-logger/backend/src/auth.js:120: token_endpoint: doc.token_endpoint,
/volume2/docker/payments-logger/backend/src/auth.js:123: grant_types_supported: doc.grant_types_supported || ['authorization_code', 'refresh_token'],
/volume2/docker/payments-logger/backend/src/auth.js:124: [API_KEY]: doc.[API_KEY] || ['none', 'client_secret_basic'],
/volume2/docker/payments-logger/backend/src/auth.js:128: id_token_signing_alg_values_supported: doc.id_token_signing_alg_values_supported || ['RS256'],
/volume2/docker/payments-logger/backend/src/routes/payments.js:58:// ── Ingest a payment (public — no auth) ──────────────────────────────────────
Bash
IN
find /volume2/docker/payments-logger/frontend/src -type f -name "*.js" -o -name "*.jsx" -o -name "*.ts" -o -name "*.tsx" | head -20
Copy code to clipboard
OUT
/volume2/docker/payments-logger/frontend/src/main.jsx
/volume2/docker/payments-logger/frontend/src/App.jsx
/volume2/docker/payments-logger/frontend/src/auth.js
/volume2/docker/payments-logger/frontend/src/components/PaymentCard.jsx
/volume2/docker/payments-logger/frontend/src/components/PaymentList.jsx
/volume2/docker/payments-logger/frontend/src/components/FilterBar.jsx
/volume2/docker/payments-logger/frontend/src/components/PaymentTable.jsx
/volume2/docker/payments-logger/frontend/src/components/AuthProvider.jsx
/volume2/docker/payments-logger/frontend/src/components/AuthCallback.jsx
Read
AuthProvider.jsx
AuthProvider.jsx
Read
AuthCallback.jsx
AuthCallback.jsx
Read
App.jsx
App.jsx
Read
main.jsx
main.jsx
Read
vite.config.js
vite.config.js
Bash
IN
grep -r "HYDRA\|VITE" /volume2/docker/payments-logger --include=".env*" -n
Copy code to clipboard
OUT
(Bash completed with no output)
Read
docker-compose.yml
docker-compose.yml
Bash
IN
grep -r "API_KEY" /volume2/docker/payments-logger/backend --include="*.js" -n
Copy code to clipboard
OUT
(Bash completed with no output)
Read
README.md
README.md
Bash
IN
grep -n "HYDRA\|oauth\|TOKEN" /volume2/docker/payments-logger/backend/src/index.js /volume2/docker/payments-logger/backend/src/auth.js | head -40
Copy code to clipboard
OUT
/volume2/docker/payments-logger/backend/src/auth.js:6: * - wellKnownRouter — serves /.well-known/oauth-* discovery endpoints
/volume2/docker/payments-logger/backend/src/auth.js:11:const HYDRA_PUBLIC_URL = (process.env.HYDRA_PUBLIC_URL || '').replace(/\/$/, '');
/volume2/docker/payments-logger/backend/src/auth.js:24: new URL(`${HYDRA_PUBLIC_URL}/.well-known/jwks.json`)
/volume2/docker/payments-logger/backend/src/auth.js:39: `resource_metadata="${realm}/.well-known/oauth-protected-resource"`,
/volume2/docker/payments-logger/backend/src/auth.js:40: `authorization_server="${HYDRA_PUBLIC_URL}"`,
/volume2/docker/payments-logger/backend/src/auth.js:58: '/.well-known/oauth-protected-resource',
/volume2/docker/payments-logger/backend/src/auth.js:59: '/.well-known/oauth-authorization-server',
/volume2/docker/payments-logger/backend/src/auth.js:78: issuer: HYDRA_PUBLIC_URL,
/volume2/docker/payments-logger/backend/src/auth.js:81: if (process.env.TOKEN_AUDIENCE) verifyOptions.audience = process.env.TOKEN_AUDIENCE;
/volume2/docker/payments-logger/backend/src/auth.js:98:wellKnownRouter.get('/.well-known/oauth-protected-resource', (_req, res) => {
/volume2/docker/payments-logger/backend/src/auth.js:103: authorization_servers: [HYDRA_PUBLIC_URL],
/volume2/docker/payments-logger/backend/src/auth.js:107: jwks_uri: `${HYDRA_PUBLIC_URL}/.well-known/jwks.json`,
/volume2/docker/payments-logger/backend/src/auth.js:111:wellKnownRouter.get('/.well-known/oauth-authorization-server', async (_req, res) => {
/volume2/docker/payments-logger/backend/src/auth.js:113: const r = await fetch(`${HYDRA_PUBLIC_URL}/.well-known/openid-configuration`);
/volume2/docker/payments-logger/backend/src/auth.js:118: issuer: doc.issuer || HYDRA_PUBLIC_URL,
Thinking
Thinking
payments-logger Authorization Overview
payments-logger Authorization Overview
The project uses
OAuth 2.1 with PKCE
via an external Hydra OAuth server at
hydra.lakylak.xyz
.
Auth Flow
Auth Flow
Frontend
(
frontend/src/auth.js
frontend/src/auth.js
):
Fetches OAuth server metadata via discovery endpoint
Generates a PKCE code verifier/challenge (SHA-256)
Redirects user to Hydra login with
code_challenge
On callback, exchanges code + verifier for tokens
Stores
access_token
,
refresh_token
in
localStorage
(
pl_oauth_tokens
)
Auto-refreshes token 30 seconds before expiry
Backend
(
backend/src/auth.js
backend/src/auth.js
):
bearerTokenMiddleware
validates the
Authorization: Bearer <token>
header
Fetches Hydra's JWKS (cached 300s) and verifies JWT signature (RS256/ES256/PS256)
Validates issuer (
https://hydra.lakylak.xyz
) and optional audience
Enforcement
Enforcement
Applied globally in
backend/src/index.js:19
backend/src/index.js:19
with these
public (unprotected) paths
:
/.well-known/oauth-protected-resource
/.well-known/oauth-authorization-server
/api/health
/api/payments/ingest
(rate-limited at 200 req/min — for SMS ingestion)
Roles/Permissions
Roles/Permissions
No RBAC
— it's binary: authenticated vs. unauthenticated. Required scopes:
openid
,
offline_access
.
Key Security Notes
Key Security Notes
PKCE
prevents authorization code interception
State parameter
provides CSRF protection
No server-side token storage
— validation is stateless via JWKS
The README/API docs mention an
X-API-Key
header, but that's
outdated
— the actual code uses Bearer tokens only
Config lives in
docker-compose.yml
docker-compose.yml
(lines 30–33):
HYDRA_PUBLIC_URL
,
REQUIRED_SCOPES
,
OAUTH_CLIENT_ID
, and optionally
TOKEN_AUDIENCE
/
JWKS_CACHE_TTL
.
Message actions
compare it to location logger and make it the same. Lets remove hydra and only use authentic (or whatever location logger uses).
Thinking
Thinking
Let me first explore how location-logger handles authorization.
Agent:
Explore location-logger authorization code
IN
Explore the location-logger project at /volume2/docker/location-logger and give me a thorough understanding of how authorization works. I need to know:
1. What auth mechanism is used (JWT, sessions, API keys, OAuth, etc.)
2. Where auth is enforced (middleware, decorators, route guards, etc.)
3. What roles/permissions exist
4. How tokens are issued, validated, and refreshed
5. Any auth-related config (env vars, settings)
6. Frontend auth flow (how the user logs in, how tokens are stored and used)
7. The full directory/file structure of the project
Please read ALL relevant source files completely and give me a detailed summary with file paths and line numbers. I need enough detail to replicate this auth system in another project.
Bash
IN
find /volume2/docker/location-logger -type f -name "*.py" -o -name "*.js" -o -name "*.ts" -o -name "*.json" | head -50
Copy code to clipboard
OUT
/volume2/docker/location-logger/.mcp.json
/volume2/docker/location-logger/app/__init__.py
/volume2/docker/location-logger/app/utils.py
/volume2/docker/location-logger/app/config.py
/volume2/docker/location-logger/app/main.py
/volume2/docker/location-logger/alembic/env.py
/volume2/docker/location-logger/mcp-server/server.py
/volume2/docker/location-logger/alembic/versions/20260203_201500_create_location_points_table.py
/volume2/docker/location-logger/alembic/versions/20260209_200000_add_enhanced_fields_and_tables.py
/volume2/docker/location-logger/alembic/versions/20260214_000000_add_users_and_audit_logs.py
/volume2/docker/location-logger/alembic/versions/20260320_000000_add_audit_query_string.py
/volume2/docker/location-logger/app/services/geofence_service.py
/volume2/docker/location-logger/app/services/recorder_service.py
/volume2/docker/location-logger/app/services/trip_service.py
/volume2/docker/location-logger/app/services/enhanced_location_service.py
/volume2/docker/location-logger/app/services/geocoding_service.py
/volume2/docker/location-logger/app/clients/__init__.py
/volume2/docker/location-logger/app/clients/dawarich_client.py
/volume2/docker/location-logger/app/clients/owntracks_client.py
/volume2/docker/location-logger/app/models/areas.py
/volume2/docker/location-logger/app/models/geofence_events.py
/volume2/docker/location-logger/app/models/trips.py
/volume2/docker/location-logger/app/models/user.py
/volume2/docker/location-logger/app/models/location.py
/volume2/docker/location-logger/app/models/audit_log.py
/volume2/docker/location-logger/app/auth/__init__.py
/volume2/docker/location-logger/app/auth/dependencies.py
/volume2/docker/location-logger/app/auth/utils.py
/volume2/docker/location-logger/app/api/enhanced_endpoints.py
/volume2/docker/location-logger/app/db/base.py
/volume2/docker/location-logger/app/db/session.py
Bash
IN
tree -L 4 /volume2/docker/location-logger 2>/dev/null || find /volume2/docker/location-logger -type d | sort
Copy code to clipboard
OUT
/volume2/docker/location-logger
├── alembic
│ ├── env.py
│ ├── script.py.mako
│ └── versions
│ ├── 20260203_201500_create_location_points_table.py
│ ├── 20260209_200000_add_enhanced_fields_and_tables.py
│ ├── 20260214_000000_add_users_and_audit_logs.py
│ ├── 20260320_000000_add_audit_query_string.py
│ └── __pycache__
│ └── 20260214_000000_add_users_and_audit_logs.cpython-311.pyc
├── alembic.ini
├── app
│ ├── api
│ │ └── enhanced_endpoints.py
│ ├── auth
│ │ ├── dependencies.py
│ │ ├── __init__.py
│ │ ├── __pycache__
│ │ │ ├── dependencies.cpython-311.pyc
│ │ │ ├── __init__.cpython-311.pyc
│ │ │ └── utils.cpython-311.pyc
│ │ └── utils.py
│ ├── clients
│ │ ├── dawarich_client.py
│ │ ├── __init__.py
│ │ └── owntracks_client.py
│ ├── config.py
│ ├── db
│ │ ├── base.py
│ │ └── session.py
│ ├── __init__.py
│ ├── main.py
│ ├── models
│ │ ├── areas.py
│ │ ├── audit_log.py
│ │ ├── geofence_events.py
│ │ ├── location.py
│ │ ├── __pycache__
│ │ │ ├── audit_log.cpython-311.pyc
│ │ │ └── user.cpython-311.pyc
│ │ ├── trips.py
│ │ └── user.py
│ ├── __pycache__
│ │ ├── __init__.cpython-311.pyc
│ │ └── main.cpython-311.pyc
│ ├── services
│ │ ├── enhanced_location_service.py
│ │ ├── geocoding_service.py
│ │ ├── geofence_service.py
│ │ ├── recorder_service.py
│ │ └── trip_service.py
│ ├── static
│ │ └── dashboard.html
│ └── utils.py
├── docker-compose.yml
├── Dockerfile
├── mcp-server
│ ├── Dockerfile
│ ├── requirements.txt
│ └── server.py
├── README.md
├── requirements.txt
└── today_map.html
16 directories, 48 files
Read
utils.py
utils.py
Read
dependencies.py
dependencies.py
Read
user.py
user.py
Read
config.py
config.py
Read
main.py
main.py
Read
session.py
session.py
Read
dashboard.html
dashboard.html
Read
audit_log.py
audit_log.py
Read
20260214_000000_add_users_and_audit_logs.py
20260214_000000_add_users_and_audit_logs.py
Read
20260320_000000_add_audit_query_string.py
20260320_000000_add_audit_query_string.py
Read
README.md
README.md
Read
requirements.txt
requirements.txt
Read
server.py
server.py
Read
server.py
server.py
(lines 101-400)
Thinking
Thinking
Now I have a full picture of both systems. Let me read the payments-logger source files before planning the migration.
Bash
List all payments-logger files
IN
find /volume2/docker/payments-logger -type f | grep -v node_modules | grep -v .git | sort
Copy code to clipboard
OUT
/volume2/docker/payments-logger/API.md
/volume2/docker/payments-logger/backend/Dockerfile
/volume2/docker/payments-logger/backend/.dockerignore
/volume2/docker/payments-logger/backend/package.json
/volume2/docker/payments-logger/backend/prisma/migrations/20260210_init/migration.sql
/volume2/docker/payments-logger/backend/prisma/migrations/20260210_simplify/migration.sql
/volume2/docker/payments-logger/backend/prisma/migrations/20260222_add_card/migration.sql
/volume2/docker/payments-logger/backend/prisma/migrations/migration_lock.toml
/volume2/docker/payments-logger/backend/prisma/schema.prisma
/volume2/docker/payments-logger/backend/src/auth.js
/volume2/docker/payments-logger/backend/src/index.js
/volume2/docker/payments-logger/backend/src/parser.js
/volume2/docker/payments-logger/backend/src/routes/payments.js
/volume2/docker/payments-logger/.claude/settings.local.json
/volume2/docker/payments-logger/docker-compose.yml
/volume2/docker/payments-logger/.env
/volume2/docker/payments-logger/.env.example
/volume2/docker/payments-logger/frontend/Dockerfile
/volume2/docker/payments-logger/frontend/.dockerignore
/volume2/docker/payments-logger/frontend/index.html
/volume2/docker/payments-logger/frontend/package.json
/volume2/docker/payments-logger/frontend/postcss.config.js
/volume2/docker/payments-logger/frontend/src/App.jsx
/volume2/docker/payments-logger/frontend/src/auth.js
/volume2/docker/payments-logger/frontend/src/components/AuthCallback.jsx
/volume2/docker/payments-logger/frontend/src/components/AuthProvider.jsx
/volume2/docker/payments-logger/frontend/src/components/FilterBar.jsx
/volume2/docker/payments-logger/frontend/src/components/PaymentCard.jsx
/volume2/docker/payments-logger/frontend/src/components/PaymentList.jsx
/volume2/docker/payments-logger/frontend/src/components/PaymentTable.jsx
/volume2/docker/payments-logger/frontend/src/index.css
/volume2/docker/payments-logger/frontend/src/main.jsx
/volume2/docker/payments-logger/frontend/tailwind.config.js
/volume2/docker/payments-logger/frontend/vite.config.js
/volume2/docker/payments-logger/README.md
Read
auth.js
auth.js
Read
index.js
index.js
Read
auth.js
auth.js
Read
AuthProvider.jsx
AuthProvider.jsx
Read
package.json
package.json
Read
AuthCallback.jsx
AuthCallback.jsx
Read
schema.prisma
schema.prisma
Read
docker-compose.yml
docker-compose.yml
Thinking
Thinking
Now let me read the remaining frontend files.
Read
App.jsx
App.jsx
Read
package.json
package.json
Read
.env
.env
Thinking
Thinking
Let me read the remaining files before making changes.
Read
main.jsx
main.jsx
Read
vite.config.js
vite.config.js
Read
payments.js
payments.js
Thinking
Thinking
Read
.env.example
.env.example
Thinking
Thinking
Now I have everything I need. Here's what changes:
Backend:
Rewrite
auth.js
(HS256 JWT + bcrypt), add
/auth/login
+
/auth/register
endpoints, add
User
model to Prisma, new migration, remove Hydra env vars.
Frontend:
Replace PKCE flow with a simple login form in
AuthProvider
, simplify
auth.js
, remove
AuthCallback
, drop
/.well-known
proxy.
Config:
Drop all Hydra/OAuth env vars, add
JWT_SECRET
.
Let me implement everything now.
Update Todos
Add bcryptjs to backend package.json
Rewrite backend/src/auth.js (HS256 JWT + bcrypt, login/register routes)
Update backend/src/index.js (remove wellKnownRouter, mount authRouter)
Add User model to prisma/schema.prisma
Create Prisma migration for users table
Rewrite frontend/src/auth.js (simple username/password login)
Rewrite frontend/src/components/AuthProvider.jsx (login form instead of PKCE redirect)
Update frontend/src/main.jsx (remove /auth/callback handling)
Delete frontend/src/components/AuthCallback.jsx
Update frontend/vite.config.js (remove /.well-known proxy)
Update docker-compose.yml (remove Hydra vars/network, add JWT_SECRET)
Update .env and .env.example
Update Todos
Add bcryptjs to backend package.json
Rewrite backend/src/auth.js (HS256 JWT + bcrypt, login/register routes)
Update backend/src/index.js (remove wellKnownRouter, mount authRouter)
Add User model to prisma/schema.prisma
Create Prisma migration for users table
Rewrite frontend/src/auth.js (simple username/password login)
Rewrite frontend/src/components/AuthProvider.jsx (login form instead of PKCE redirect)
Update frontend/src/main.jsx (remove /auth/callback handling)
Delete frontend/src/components/AuthCallback.jsx...
|
10637
|
NULL
|
NULL
|
NULL
|
|
10652
|
477
|
43
|
2026-05-08T17:37:04.393033+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778261824393_m1.jpg...
|
Code
|
Review payment logger au… — docker [SSH: nas]
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Explorer (⇧⌘E)
Search (⇧⌘F)
Source Control (⌃⇧ Explorer (⇧⌘E)
Search (⇧⌘F)
Source Control (⌃⇧G) - 55 pending changes
55
Run and Debug (⇧⌘D)
Remote Explorer
Extensions (⇧⌘X) - 2 require update
2
Claude Code
Containers
EXPLORER
EXPLORER
Explorer Section: docker [SSH: nas]
Explorer Section: docker [SSH: nas]
DOCKER [SSH: NAS]
audiobookshelf
auth
beszel
bitwarden
dawarich
dsk-uploader
flask-app
garmin-connector
gitea
health
health-tracker
homarr
hst
immich
jellyfinht
kavita
libreoffice
linkwarden
location-logger
alembic
app
mcp-server
.env
.env.example
.gitignore
.mcp.json
M
alembic.ini
docker-compose.yml
M
Dockerfile
README.md
M
requirements.txt
M
today_map.html
mariadb
meeting-detector
mindfulmama
n8n
notifier-app
npm
oauth
obsidian
ollama
open-webui
openttd
openvpn-client
orchestrator
outfit-app
owntracks-stack
paperlessngx
payments-logger
.claude
Outline Section
OUTLINE
OUTLINE
Timeline Section
TIMELINE
TIMELINE
docker-compose.yml, Editor Group 1
docker-compose.yml, Editor Group 1
Review payment logger au…, Editor Group 2
Problems (⇧⌘M)
PROBLEMS
Output (⇧⌘U)
OUTPUT
Debug Console (⇧⌘Y)
DEBUG CONSOLE
Terminal (⌃`)
TERMINAL
Ports
PORTS
remote SSH: nas
SSH: nas
location-logger (Git)
location-logger
location-logger (Git) - main*, Checkout Branch/Tag...
main*
location-logger (Git) - Synchronize Changes
No Problems
0
0
No Ports Forwarded
0
Notifications
Sign In
Sign In
collapsed
Clear
Review payment logger authorization implementation
Session history
New session
Message actions
review payment_logger project how toes authorization work
Thinking
Thinking
Let me explore the payment_logger project structure first.
Bash
Find payment_logger project files
IN
find /volume2/docker -type f -name "*.py" -o -name "*.yml" -o -name "*.yaml" -o -name "*.env" -o -name "*.toml" -o -name "*.cfg" | grep -i payment | head -50
Copy code to clipboard
OUT
bfs: error: /volume2/docker/portnotedb/pg_commit_ts: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_dynshmem: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_notify: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_serial: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_snapshots: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_subtrans: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_twophase: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_multixact: Permission denied.
bfs: error: /volume2/docker/portnotedb/base: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_replslot: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_tblspc: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_stat: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_stat_tmp: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_xact: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_logical: Permission denied.
bfs: error: /volume2/docker/openttd/.dbus: Permission denied.
bfs: error: /volume2/docker/immich/db: Permission denied.
bfs: error: /volume2/docker/paperlessngx/db: Permission denied.
bfs: error: /volume2/docker/appflowy/postgres: Permission denied.
bfs: error: /volume2/docker/auth/db: Permission denied.
bfs: error: /volume2/docker/openttd/.XDG/dbus-1: Permission denied.
bfs: error: /volume2/docker/openttd/.config/pulse: Permission denied.
bfs: error: /volume2/docker/openttd/.cache/openbox/sessions: Permission denied.
/volume2/docker/payments-logger/.env
/volume2/docker/payments-logger/docker-compose.yml
/volume2/docker/payments-logger/backend/prisma/migrations/migration_lock.toml
Bash
List docker directory contents
IN
ls /volume2/docker/
Copy code to clipboard
OUT
adguard
ai-stack
app-db
appflowy
audiobookshelf
auth
beszel
bitwarden
dawarich
dsk-uploader
flask-app
garmin-connector
gitea
health
health-tracker
homarr
hst
immich
jellyfinht
kavita
libreoffice
linkwarden
location-logger
mariadb
meeting-detector
mindfulmama
n8n
notifier-app
npm
oauth
obsidian
ollama
openttd
openvpn-client
open-webui
orchestrator
outfit-app
owntracks-stack
paperlessngx
payments-logger
personal-log
personal-log-system
player
portainer
portnotedb
reminders-app
romm
second-brain
static
stirling
syncthing
tailscale
temp-logger
test-app
tmp
torrent-stack
tree
trilium
tubearchivist
twenty
uptimekuma
ytptube
Agent:
Explore payment_logger authorization code
IN
Explore the payments-logger project at /volume2/docker/payments-logger and give me a thorough understanding of how authorization works. I need to know:
1. What auth mechanism is used (JWT, sessions, API keys, OAuth, etc.)
2. Where auth is enforced (middleware, decorators, route guards, etc.)
3. What roles/permissions exist
4. How tokens are issued, validated, and refreshed
5. Any auth-related config (env vars, settings)
Please read the key source files and give me a clear summary with file paths and line numbers for the important parts.
Bash
IN
find /volume2/docker/payments-logger -type f -name "*.py" -o -name "*.json" -o -name "*.yml" -o -name "*.yaml" | grep -E "(auth|token|jwt|session|permission|role)" | head -20
Copy code to clipboard
OUT
(Bash completed with no output)
Bash
IN
ls -la /volume2/docker/payments-logger/ 2>/dev/null || echo "Directory not found"
Copy code to clipboard
OUT
total 36
drwxrwxrwx 1 Adm1n admin 162 Mar 29 18:01 .
drwxrwxrwx 1 root root 1146 Apr 26 18:49 ..
-rwxrwxrwx 1 Adm1n admin 15233 Feb 22 17:08 API.md
drwxrwxrwx 1 Adm1n admin 88 Mar 29 15:41 backend
drwxrwxrwx 1 Adm1n admin 38 Mar 29 17:07 .claude
-rwxrwxrwx 1 Adm1n admin 1502 Mar 29 18:01 docker-compose.yml
-rwxrwxrwx 1 Adm1n admin 1066 Mar 29 15:44 .env
-rwxrwxrwx 1 Adm1n admin 1078 Feb 14 17:53 .env.example
drwxrwxrwx 1 Adm1n admin 194 Mar 29 15:44 frontend
-rwxrwxrwx 1 Adm1n admin 19 Feb 14 17:54 .gitignore
-rwxrwxrwx 1 Adm1n admin 4052 Feb 14 19:06 README.md
Bash
IN
find /volume2/docker/payments-logger/backend -type f | head -30
Copy code to clipboard
OUT
/volume2/docker/payments-logger/backend/Dockerfile
/volume2/docker/payments-logger/backend/.dockerignore
/volume2/docker/payments-logger/backend/package.json
/volume2/docker/payments-logger/backend/prisma/schema.prisma
/volume2/docker/payments-logger/backend/src/parser.js
/volume2/docker/payments-logger/backend/src/index.js
/volume2/docker/payments-logger/backend/src/auth.js
/volume2/docker/payments-logger/backend/prisma/migrations/migration_lock.toml
/volume2/docker/payments-logger/backend/src/routes/payments.js
/volume2/docker/payments-logger/backend/prisma/migrations/20260210_init/migration.sql
/volume2/docker/payments-logger/backend/prisma/migrations/20260210_simplify/migration.sql
/volume2/docker/payments-logger/backend/prisma/migrations/20260222_add_card/migration.sql
Bash
IN
find /volume2/docker/payments-logger -type f \( -name "*.js" -o -name "*.json" -o -name "*.md" \) | sort
Copy code to clipboard
OUT
/volume2/docker/payments-logger/API.md
/volume2/docker/payments-logger/backend/package.json
/volume2/docker/payments-logger/backend/src/auth.js
/volume2/docker/payments-logger/backend/src/index.js
/volume2/docker/payments-logger/backend/src/parser.js
/volume2/docker/payments-logger/backend/src/routes/payments.js
/volume2/docker/payments-logger/.claude/settings.local.json
/volume2/docker/payments-logger/frontend/package.json
/volume2/docker/payments-logger/frontend/postcss.config.js
/volume2/docker/payments-logger/frontend/src/auth.js
/volume2/docker/payments-logger/frontend/tailwind.config.js
/volume2/docker/payments-logger/frontend/vite.config.js
/volume2/docker/payments-logger/README.md
Read
.env
.env
Read
auth.js
auth.js
Read
index.js
index.js
Read
package.json
package.json
Read
auth.js
auth.js
Read
API.md
API.md
Read
payments.js
payments.js
Read
.env.example
.env.example
Read
schema.prisma
schema.prisma
Bash
IN
grep -r "API_KEY\|auth\|token\|oauth\|hydra" /volume2/docker/payments-logger/backend/src --include="*.js" -n
Copy code to clipboard
OUT
/volume2/docker/payments-logger/backend/src/index.js:6:const { bearerTokenMiddleware, wellKnownRouter } = require('./auth');
/volume2/docker/payments-logger/backend/src/index.js:18:// ── OAuth Bearer token auth (skips public paths) ──────────────────────────────
/volume2/docker/payments-logger/backend/src/auth.js:2: * OAuth 2.1 / Hydra JWT authentication for Express.
/volume2/docker/payments-logger/backend/src/auth.js:6: * - wellKnownRouter — serves /.well-known/oauth-* discovery endpoints
/volume2/docker/payments-logger/backend/src/auth.js:33:function sendUnauthorized(res, detail, error = 'invalid_token') {
/volume2/docker/payments-logger/backend/src/auth.js:39: `resource_metadata="${realm}/.well-known/oauth-protected-resource"`,
/volume2/docker/payments-logger/backend/src/auth.js:40: `authorization_server="${HYDRA_PUBLIC_URL}"`,
/volume2/docker/payments-logger/backend/src/auth.js:52: * On success, attaches the decoded payload to req.tokenPayload.
/volume2/docker/payments-logger/backend/src/auth.js:54: * @param {Set<string>} publicPaths Paths to skip auth for.
/volume2/docker/payments-logger/backend/src/auth.js:58: '/.well-known/oauth-protected-resource',
/volume2/docker/payments-logger/backend/src/auth.js:59: '/.well-known/oauth-authorization-server',
/volume2/docker/payments-logger/backend/src/auth.js:66: const auth = req.headers.authorization || '';
/volume2/docker/payments-logger/backend/src/auth.js:67: if (!auth.toLowerCase().startsWith('bearer ')) {
/volume2/docker/payments-logger/backend/src/auth.js:68: return sendUnauthorized(res, 'Bearer token required', 'invalid_request');
/volume2/docker/payments-logger/backend/src/auth.js:71: const token = auth.slice(7).trim();
/volume2/docker/payments-logger/backend/src/auth.js:72: if (!token) {
/volume2/docker/payments-logger/backend/src/auth.js:73: return sendUnauthorized(res, 'Bearer token required', 'invalid_request');
/volume2/docker/payments-logger/backend/src/auth.js:82: const { payload } = await jwtVerify(token, getJwks(), verifyOptions);
/volume2/docker/payments-logger/backend/src/auth.js:83: req.tokenPayload = payload;
/volume2/docker/payments-logger/backend/src/auth.js:87: const error = msg.includes('expired') ? 'invalid_token' : 'invalid_token';
/volume2/docker/payments-logger/backend/src/auth.js:88: sendUnauthorized(res, msg, error);
/volume2/docker/payments-logger/backend/src/auth.js:98:wellKnownRouter.get('/.well-known/oauth-protected-resource', (_req, res) => {
/volume2/docker/payments-logger/backend/src/auth.js:103: authorization_servers: [HYDRA_PUBLIC_URL],
/volume2/docker/payments-logger/backend/src/auth.js:111:wellKnownRouter.get('/.well-known/oauth-authorization-server', async (_req, res) => {
/volume2/docker/payments-logger/backend/src/auth.js:119: authorization_endpoint: doc.authorization_endpoint,
/volume2/docker/payments-logger/backend/src/auth.js:120: token_endpoint: doc.token_endpoint,
/volume2/docker/payments-logger/backend/src/auth.js:123: grant_types_supported: doc.grant_types_supported || ['authorization_code', 'refresh_token'],
/volume2/docker/payments-logger/backend/src/auth.js:124: [API_KEY]: doc.[API_KEY] || ['none', 'client_secret_basic'],
/volume2/docker/payments-logger/backend/src/auth.js:128: id_token_signing_alg_values_supported: doc.id_token_signing_alg_values_supported || ['RS256'],
/volume2/docker/payments-logger/backend/src/routes/payments.js:58:// ── Ingest a payment (public — no auth) ──────────────────────────────────────
Bash
IN
find /volume2/docker/payments-logger/frontend/src -type f -name "*.js" -o -name "*.jsx" -o -name "*.ts" -o -name "*.tsx" | head -20
Copy code to clipboard
OUT
/volume2/docker/payments-logger/frontend/src/main.jsx
/volume2/docker/payments-logger/frontend/src/App.jsx
/volume2/docker/payments-logger/frontend/src/auth.js
/volume2/docker/payments-logger/frontend/src/components/PaymentCard.jsx
/volume2/docker/payments-logger/frontend/src/components/PaymentList.jsx
/volume2/docker/payments-logger/frontend/src/components/FilterBar.jsx
/volume2/docker/payments-logger/frontend/src/components/PaymentTable.jsx
/volume2/docker/payments-logger/frontend/src/components/AuthProvider.jsx
/volume2/docker/payments-logger/frontend/src/components/AuthCallback.jsx
Read
AuthProvider.jsx
AuthProvider.jsx
Read
AuthCallback.jsx
AuthCallback.jsx
Read
App.jsx
App.jsx
Read
main.jsx
main.jsx
Read
vite.config.js
vite.config.js
Bash
IN
grep -r "HYDRA\|VITE" /volume2/docker/payments-logger --include=".env*" -n
Copy code to clipboard
OUT
(Bash completed with no output)
Read
docker-compose.yml
docker-compose.yml
Bash
IN
grep -r "API_KEY" /volume2/docker/payments-logger/backend --include="*.js" -n
Copy code to clipboard
OUT
(Bash completed with no output)
Read
README.md
README.md
Bash
IN
grep -n "HYDRA\|oauth\|TOKEN" /volume2/docker/payments-logger/backend/src/index.js /volume2/docker/payments-logger/backend/src/auth.js | head -40
Copy code to clipboard
OUT
/volume2/docker/payments-logger/backend/src/auth.js:6: * - wellKnownRouter — serves /.well-known/oauth-* discovery endpoints
/volume2/docker/payments-logger/backend/src/auth.js:11:const HYDRA_PUBLIC_URL = (process.env.HYDRA_PUBLIC_URL || '').replace(/\/$/, '');
/volume2/docker/payments-logger/backend/src/auth.js:24: new URL(`${HYDRA_PUBLIC_URL}/.well-known/jwks.json`)
/volume2/docker/payments-logger/backend/src/auth.js:39: `resource_metadata="${realm}/.well-known/oauth-protected-resource"`,
/volume2/docker/payments-logger/backend/src/auth.js:40: `authorization_server="${HYDRA_PUBLIC_URL}"`,
/volume2/docker/payments-logger/backend/src/auth.js:58: '/.well-known/oauth-protected-resource',
/volume2/docker/payments-logger/backend/src/auth.js:59: '/.well-known/oauth-authorization-server',
/volume2/docker/payments-logger/backend/src/auth.js:78: issuer: HYDRA_PUBLIC_URL,
/volume2/docker/payments-logger/backend/src/auth.js:81: if (process.env.TOKEN_AUDIENCE) verifyOptions.audience = process.env.TOKEN_AUDIENCE;
/volume2/docker/payments-logger/backend/src/auth.js:98:wellKnownRouter.get('/.well-known/oauth-protected-resource', (_req, res) => {
/volume2/docker/payments-logger/backend/src/auth.js:103: authorization_servers: [HYDRA_PUBLIC_URL],
/volume2/docker/payments-logger/backend/src/auth.js:107: jwks_uri: `${HYDRA_PUBLIC_URL}/.well-known/jwks.json`,
/volume2/docker/payments-logger/backend/src/auth.js:111:wellKnownRouter.get('/.well-known/oauth-authorization-server', async (_req, res) => {
/volume2/docker/payments-logger/backend/src/auth.js:113: const r = await fetch(`${HYDRA_PUBLIC_URL}/.well-known/openid-configuration`);
/volume2/docker/payments-logger/backend/src/auth.js:118: issuer: doc.issuer || HYDRA_PUBLIC_URL,
Thinking
Thinking
payments-logger Authorization Overview
payments-logger Authorization Overview
The project uses
OAuth 2.1 with PKCE
via an external Hydra OAuth server at
hydra.lakylak.xyz
.
Auth Flow
Auth Flow
Frontend
(
frontend/src/auth.js
frontend/src/auth.js
):
Fetches OAuth server metadata via discovery endpoint
Generates a PKCE code verifier/challenge (SHA-256)
Redirects user to Hydra login with
code_challenge
On callback, exchanges code + verifier for tokens
Stores
access_token
,
refresh_token
in
localStorage
(
pl_oauth_tokens
)
Auto-refreshes token 30 seconds before expiry
Backend
(
backend/src/auth.js
backend/src/auth.js
):
bearerTokenMiddleware
validates the
Authorization: Bearer <token>
header
Fetches Hydra's JWKS (cached 300s) and verifies JWT signature (RS256/ES256/PS256)
Validates issuer (
https://hydra.lakylak.xyz
) and optional audience
Enforcement
Enforcement
Applied globally in
backend/src/index.js:19
backend/src/index.js:19
with these
public (unprotected) paths
:
/.well-known/oauth-protected-resource
/.well-known/oauth-authorization-server
/api/health
/api/payments/ingest
(rate-limited at 200 req/min — for SMS ingestion)
Roles/Permissions
Roles/Permissions
No RBAC
— it's binary: authenticated vs. unauthenticated. Required scopes:
openid
,
offline_access
.
Key Security Notes
Key Security Notes
PKCE
prevents authorization code interception
State parameter
provides CSRF protection
No server-side token storage
— validation is stateless via JWKS
The README/API docs mention an
X-API-Key
header, but that's
outdated
— the actual code uses Bearer tokens only
Config lives in
docker-compose.yml
docker-compose.yml
(lines 30–33):
HYDRA_PUBLIC_URL
,
REQUIRED_SCOPES
,
OAUTH_CLIENT_ID
, and optionally
TOKEN_AUDIENCE
/
JWKS_CACHE_TTL
.
Message actions
compare it to location logger and make it the same. Lets remove hydra and only use authentic (or whatever location logger uses).
Thinking
Thinking
Let me first explore how location-logger handles authorization.
Agent:
Explore location-logger authorization code
IN
Explore the location-logger project at /volume2/docker/location-logger and give me a thorough understanding of how authorization works. I need to know:
1. What auth mechanism is used (JWT, sessions, API keys, OAuth, etc.)
2. Where auth is enforced (middleware, decorators, route guards, etc.)
3. What roles/permissions exist
4. How tokens are issued, validated, and refreshed
5. Any auth-related config (env vars, settings)
6. Frontend auth flow (how the user logs in, how tokens are stored and used)
7. The full directory/file structure of the project
Please read ALL relevant source files completely and give me a detailed summary with file paths and line numbers. I need enough detail to replicate this auth system in another project.
Bash
IN
find /volume2/docker/location-logger -type f -name "*.py" -o -name "*.js" -o -name "*.ts" -o -name "*.json" | head -50
Copy code to clipboard
OUT
/volume2/docker/location-logger/.mcp.json
/volume2/docker/location-logger/app/__init__.py
/volume2/docker/location-logger/app/utils.py
/volume2/docker/location-logger/app/config.py
/volume2/docker/location-logger/app/main.py
/volume2/docker/location-logger/alembic/env.py
/volume2/docker/location-logger/mcp-server/server.py
/volume2/docker/location-logger/alembic/versions/20260203_201500_create_location_points_table.py
/volume2/docker/location-logger/alembic/versions/20260209_200000_add_enhanced_fields_and_tables.py
/volume2/docker/location-logger/alembic/versions/20260214_000000_add_users_and_audit_logs.py
/volume2/docker/location-logger/alembic/versions/20260320_000000_add_audit_query_string.py
/volume2/docker/location-logger/app/services/geofence_service.py
/volume2/docker/location-logger/app/services/recorder_service.py
/volume2/docker/location-logger/app/services/trip_service.py
/volume2/docker/location-logger/app/services/enhanced_location_service.py
/volume2/docker/location-logger/app/services/geocoding_service.py
/volume2/docker/location-logger/app/clients/__init__.py
/volume2/docker/location-logger/app/clients/dawarich_client.py
/volume2/docker/location-logger/app/clients/owntracks_client.py
/volume2/docker/location-logger/app/models/areas.py
/volume2/docker/location-logger/app/models/geofence_events.py
/volume2/docker/location-logger/app/models/trips.py
/volume2/docker/location-logger/app/models/user.py
/volume2/docker/location-logger/app/models/location.py
/volume2/docker/location-logger/app/models/audit_log.py
/volume2/docker/location-logger/app/auth/__init__.py
/volume2/docker/location-logger/app/auth/dependencies.py
/volume2/docker/location-logger/app/auth/utils.py
/volume2/docker/location-logger/app/api/enhanced_endpoints.py
/volume2/docker/location-logger/app/db/base.py
/volume2/docker/location-logger/app/db/session.py
Bash
IN
tree -L 4 /volume2/docker/location-logger 2>/dev/null || find /volume2/docker/location-logger -type d | sort
Copy code to clipboard
OUT
/volume2/docker/location-logger
├── alembic
│ ├── env.py
│ ├── script.py.mako
│ └── versions
│ ├── 20260203_201500_create_location_points_table.py
│ ├── 20260209_200000_add_enhanced_fields_and_tables.py
│ ├── 20260214_000000_add_users_and_audit_logs.py
│ ├── 20260320_000000_add_audit_query_string.py
│ └── __pycache__
│ └── 20260214_000000_add_users_and_audit_logs.cpython-311.pyc
├── alembic.ini
├── app
│ ├── api
│ │ └── enhanced_endpoints.py
│ ├── auth
│ │ ├── dependencies.py
│ │ ├── __init__.py
│ │ ├── __pycache__
│ │ │ ├── dependencies.cpython-311.pyc
│ │ │ ├── __init__.cpython-311.pyc
│ │ │ └── utils.cpython-311.pyc
│ │ └── utils.py
│ ├── clients
│ │ ├── dawarich_client.py
│ │ ├── __init__.py
│ │ └── owntracks_client.py
│ ├── config.py
│ ├── db
│ │ ├── base.py
│ │ └── session.py
│ ├── __init__.py
│ ├── main.py
│ ├── models
│ │ ├── areas.py
│ │ ├── audit_log.py
│ │ ├── geofence_events.py
│ │ ├── location.py
│ │ ├── __pycache__
│ │ │ ├── audit_log.cpython-311.pyc
│ │ │ └── user.cpython-311.pyc
│ │ ├── trips.py
│ │ └── user.py
│ ├── __pycache__
│ │ ├── __init__.cpython-311.pyc
│ │ └── main.cpython-311.pyc
│ ├── services
│ │ ├── enhanced_location_service.py
│ │ ├── geocoding_service.py
│ │ ├── geofence_service.py
│ │ ├── recorder_service.py
│ │ └── trip_service.py
│ ├── static
│ │ └── dashboard.html
│ └── utils.py
├── docker-compose.yml
├── Dockerfile
├── mcp-server
│ ├── Dockerfile
│ ├── requirements.txt
│ └── server.py
├── README.md
├── requirements.txt
└── today_map.html
16 directories, 48 files
Read
utils.py
utils.py
Read
dependencies.py
dependencies.py
Read
user.py
user.py
Read
config.py
config.py
Read
main.py
main.py
Read
session.py
session.py
Read
dashboard.html
dashboard.html
Read
audit_log.py
audit_log.py
Read
20260214_000000_add_users_and_audit_logs.py
20260214_000000_add_users_and_audit_logs.py
Read
20260320_000000_add_audit_query_string.py
20260320_000000_add_audit_query_string.py
Read
README.md
README.md
Read
requirements.txt
requirements.txt
Read
server.py
server.py
Read
server.py
server.py
(lines 101-400)
Thinking
Thinking
Now I have a full picture of both systems. Let me read the payments-logger source files before planning the migration.
Bash
List all payments-logger files
IN
find /volume2/docker/payments-logger -type f | grep -v node_modules | grep -v .git | sort
Copy code to clipboard
OUT
/volume2/docker/payments-logger/API.md
/volume2/docker/payments-logger/backend/Dockerfile
/volume2/docker/payments-logger/backend/.dockerignore
/volume2/docker/payments-logger/backend/package.json
/volume2/docker/payments-logger/backend/prisma/migrations/20260210_init/migration.sql
/volume2/docker/payments-logger/backend/prisma/migrations/20260210_simplify/migration.sql
/volume2/docker/payments-logger/backend/prisma/migrations/20260222_add_card/migration.sql
/volume2/docker/payments-logger/backend/prisma/migrations/migration_lock.toml
/volume2/docker/payments-logger/backend/prisma/schema.prisma
/volume2/docker/payments-logger/backend/src/auth.js
/volume2/docker/payments-logger/backend/src/index.js
/volume2/docker/payments-logger/backend/src/parser.js
/volume2/docker/payments-logger/backend/src/routes/payments.js
/volume2/docker/payments-logger/.claude/settings.local.json
/volume2/docker/payments-logger/docker-compose.yml
/volume2/docker/payments-logger/.env
/volume2/docker/payments-logger/.env.example
/volume2/docker/payments-logger/frontend/Dockerfile
/volume2/docker/payments-logger/frontend/.dockerignore
/volume2/docker/payments-logger/frontend/index.html
/volume2/docker/payments-logger/frontend/package.json
/volume2/docker/payments-logger/frontend/postcss.config.js
/volume2/docker/payments-logger/frontend/src/App.jsx
/volume2/docker/payments-logger/frontend/src/auth.js
/volume2/docker/payments-logger/frontend/src/components/AuthCallback.jsx
/volume2/docker/payments-logger/frontend/src/components/AuthProvider.jsx
/volume2/docker/payments-logger/frontend/src/components/FilterBar.jsx
/volume2/docker/payments-logger/frontend/src/components/PaymentCard.jsx
/volume2/docker/payments-logger/frontend/src/components/PaymentList.jsx
/volume2/docker/payments-logger/frontend/src/components/PaymentTable.jsx
/volume2/docker/payments-logger/frontend/src/index.css
/volume2/docker/payments-logger/frontend/src/main.jsx
/volume2/docker/payments-logger/frontend/tailwind.config.js
/volume2/docker/payments-logger/frontend/vite.config.js
/volume2/docker/payments-logger/README.md
Read
auth.js
auth.js
Read
index.js
index.js
Read
auth.js
auth.js
Read
AuthProvider.jsx
AuthProvider.jsx
Read
package.json
package.json
Read
AuthCallback.jsx
AuthCallback.jsx
Read
schema.prisma
schema.prisma
Read
docker-compose.yml
docker-compose.yml
Thinking
Thinking
Now let me read the remaining frontend files.
Read
App.jsx
App.jsx
Read
package.json
package.json
Read
.env
.env
Thinking
Thinking
Let me read the remaining files before making changes.
Read
main.jsx
main.jsx
Read
vite.config.js
vite.config.js
Read
payments.js
payments.js
Thinking
Thinking
Read
.env.example
.env.example
Thinking
Thinking
Now I have everything I need. Here's what changes:
Backend:
Rewrite
auth.js
(HS256 JWT + bcrypt), add
/auth/login
+
/auth/register
endpoints, add
User
model to Prisma, new migration, remove Hydra env vars.
Frontend:
Replace PKCE flow with a simple login form in
AuthProvider
, simplify
auth.js
, remove
AuthCallback
, drop
/.well-known
proxy.
Config:
Drop all Hydra/OAuth env vars, add
JWT_SECRET
.
Let me implement everything now.
Update Todos
Add bcryptjs to backend package.json
Rewrite backend/src/auth.js (HS256 JWT + bcrypt, login/register routes)
Update backend/src/index.js (remove wellKnownRouter, mount authRouter)
Add User model to prisma/schema.prisma
Create Prisma migration for users table...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Explorer (⇧⌘E)","depth":19,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":true},{"role":"AXStaticText","text":"","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Search (⇧⌘F)","depth":19,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Source Control (⌃⇧G) - 55 pending changes","depth":19,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"55","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Run and Debug (⇧⌘D)","depth":19,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Remote Explorer","depth":19,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Extensions (⇧⌘X) - 2 require update","depth":19,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"2","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Claude Code","depth":19,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"Containers","depth":19,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"EXPLORER","depth":17,"on_screen":true,"role_description":"heading"},{"role":"AXStaticText","text":"EXPLORER","depth":18,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Explorer Section: docker [SSH: nas]","depth":21,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXHeading","text":"Explorer Section: docker [SSH: nas]","depth":22,"on_screen":true,"role_description":"heading"},{"role":"AXStaticText","text":"DOCKER [SSH: NAS]","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"audiobookshelf","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"auth","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"beszel","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"bitwarden","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"dawarich","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"dsk-uploader","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"flask-app","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"garmin-connector","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"gitea","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"health","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"health-tracker","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"homarr","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"hst","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"immich","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jellyfinht","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"kavita","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"libreoffice","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"linkwarden","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"location-logger","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"alembic","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"app","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"mcp-server","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":".env","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":".env.example","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":".gitignore","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":".mcp.json","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"M","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"alembic.ini","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"docker-compose.yml","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"M","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Dockerfile","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"README.md","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"M","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"requirements.txt","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"M","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"today_map.html","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"mariadb","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"meeting-detector","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"mindfulmama","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"n8n","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"notifier-app","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"npm","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"oauth","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"obsidian","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ollama","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"open-webui","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"openttd","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"openvpn-client","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"orchestrator","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"outfit-app","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"owntracks-stack","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"paperlessngx","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"payments-logger","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":".claude","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Outline Section","depth":21,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXHeading","text":"OUTLINE","depth":22,"on_screen":true,"role_description":"heading"},{"role":"AXStaticText","text":"OUTLINE","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Timeline Section","depth":21,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXHeading","text":"TIMELINE","depth":22,"on_screen":true,"role_description":"heading"},{"role":"AXStaticText","text":"TIMELINE","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"docker-compose.yml, Editor Group 1","depth":28,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"","depth":29,"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"docker-compose.yml, Editor Group 1","depth":28,"on_screen":true,"role_description":"editor","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"Review payment logger au…, Editor Group 2","depth":28,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXRadioButton","text":"Problems (⇧⌘M)","depth":22,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"PROBLEMS","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Output (⇧⌘U)","depth":22,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUTPUT","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Debug Console (⇧⌘Y)","depth":22,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"DEBUG CONSOLE","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Terminal (⌃`)","depth":22,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":true},{"role":"AXStaticText","text":"TERMINAL","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Ports","depth":22,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"PORTS","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"remote SSH: nas","depth":16,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":17,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"SSH: nas","depth":17,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"location-logger (Git)","depth":16,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":17,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"location-logger","depth":17,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"location-logger (Git) - main*, Checkout Branch/Tag...","depth":16,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":17,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"main*","depth":17,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"location-logger (Git) - Synchronize Changes","depth":16,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"No Problems","depth":16,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":17,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"0","depth":17,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":17,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"0","depth":17,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"No Ports Forwarded","depth":16,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":17,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"0","depth":17,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Notifications","depth":16,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sign In","depth":16,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":17,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Sign In","depth":17,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"collapsed","depth":12,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Clear","depth":12,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Review payment logger authorization implementation","depth":19,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Session history","depth":19,"on_screen":true,"help_text":"Session history","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New session","depth":19,"on_screen":true,"help_text":"New session","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Message actions","depth":24,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"review payment_logger project how toes authorization work","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":23,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Thinking","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Let me explore the payment_logger project structure first.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Find payment_logger project files","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"find /volume2/docker -type f -name \"*.py\" -o -name \"*.yml\" -o -name \"*.yaml\" -o -name \"*.env\" -o -name \"*.toml\" -o -name \"*.cfg\" | grep -i payment | head -50","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"bfs: error: /volume2/docker/portnotedb/pg_commit_ts: Permission denied.\nbfs: error: /volume2/docker/portnotedb/pg_dynshmem: Permission denied.\nbfs: error: /volume2/docker/portnotedb/pg_notify: Permission denied.\nbfs: error: /volume2/docker/portnotedb/pg_serial: Permission denied.\nbfs: error: /volume2/docker/portnotedb/pg_snapshots: Permission denied.\nbfs: error: /volume2/docker/portnotedb/pg_subtrans: Permission denied.\nbfs: error: /volume2/docker/portnotedb/pg_twophase: Permission denied.\nbfs: error: /volume2/docker/portnotedb/pg_multixact: Permission denied.\nbfs: error: /volume2/docker/portnotedb/base: Permission denied.\nbfs: error: /volume2/docker/portnotedb/pg_replslot: Permission denied.\nbfs: error: /volume2/docker/portnotedb/pg_tblspc: Permission denied.\nbfs: error: /volume2/docker/portnotedb/pg_stat: Permission denied.\nbfs: error: /volume2/docker/portnotedb/pg_stat_tmp: Permission denied.\nbfs: error: /volume2/docker/portnotedb/pg_xact: Permission denied.\nbfs: error: /volume2/docker/portnotedb/pg_logical: Permission denied.\nbfs: error: /volume2/docker/openttd/.dbus: Permission denied.\nbfs: error: /volume2/docker/immich/db: Permission denied.\nbfs: error: /volume2/docker/paperlessngx/db: Permission denied.\nbfs: error: /volume2/docker/appflowy/postgres: Permission denied.\nbfs: error: /volume2/docker/auth/db: Permission denied.\nbfs: error: /volume2/docker/openttd/.XDG/dbus-1: Permission denied.\nbfs: error: /volume2/docker/openttd/.config/pulse: Permission denied.\nbfs: error: /volume2/docker/openttd/.cache/openbox/sessions: Permission denied.\n/volume2/docker/payments-logger/.env\n/volume2/docker/payments-logger/docker-compose.yml\n/volume2/docker/payments-logger/backend/prisma/migrations/migration_lock.toml","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"List docker directory contents","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ls /volume2/docker/","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"adguard\nai-stack\napp-db\nappflowy\naudiobookshelf\nauth\nbeszel\nbitwarden\ndawarich\ndsk-uploader\nflask-app\ngarmin-connector\ngitea\nhealth\nhealth-tracker\nhomarr\nhst\nimmich\njellyfinht\nkavita\nlibreoffice\nlinkwarden\nlocation-logger\nmariadb\nmeeting-detector\nmindfulmama\nn8n\nnotifier-app\nnpm\noauth\nobsidian\nollama\nopenttd\nopenvpn-client\nopen-webui\norchestrator\noutfit-app\nowntracks-stack\npaperlessngx\npayments-logger\npersonal-log\npersonal-log-system\nplayer\nportainer\nportnotedb\nreminders-app\nromm\nsecond-brain\nstatic\nstirling\nsyncthing\ntailscale\ntemp-logger\ntest-app\ntmp\ntorrent-stack\ntree\ntrilium\ntubearchivist\ntwenty\nuptimekuma\nytptube","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Agent:","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Explore payment_logger authorization code","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Explore the payments-logger project at /volume2/docker/payments-logger and give me a thorough understanding of how authorization works. I need to know:\n\n1. What auth mechanism is used (JWT, sessions, API keys, OAuth, etc.)\n2. Where auth is enforced (middleware, decorators, route guards, etc.)\n3. What roles/permissions exist\n4. How tokens are issued, validated, and refreshed\n5. Any auth-related config (env vars, settings)\n\nPlease read the key source files and give me a clear summary with file paths and line numbers for the important parts.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"find /volume2/docker/payments-logger -type f -name \"*.py\" -o -name \"*.json\" -o -name \"*.yml\" -o -name \"*.yaml\" | grep -E \"(auth|token|jwt|session|permission|role)\" | head -20","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"(Bash completed with no output)","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ls -la /volume2/docker/payments-logger/ 2>/dev/null || echo \"Directory not found\"","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"total 36\ndrwxrwxrwx 1 Adm1n admin 162 Mar 29 18:01 .\ndrwxrwxrwx 1 root root 1146 Apr 26 18:49 ..\n-rwxrwxrwx 1 Adm1n admin 15233 Feb 22 17:08 API.md\ndrwxrwxrwx 1 Adm1n admin 88 Mar 29 15:41 backend\ndrwxrwxrwx 1 Adm1n admin 38 Mar 29 17:07 .claude\n-rwxrwxrwx 1 Adm1n admin 1502 Mar 29 18:01 docker-compose.yml\n-rwxrwxrwx 1 Adm1n admin 1066 Mar 29 15:44 .env\n-rwxrwxrwx 1 Adm1n admin 1078 Feb 14 17:53 .env.example\ndrwxrwxrwx 1 Adm1n admin 194 Mar 29 15:44 frontend\n-rwxrwxrwx 1 Adm1n admin 19 Feb 14 17:54 .gitignore\n-rwxrwxrwx 1 Adm1n admin 4052 Feb 14 19:06 README.md","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"find /volume2/docker/payments-logger/backend -type f | head -30","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/volume2/docker/payments-logger/backend/Dockerfile\n/volume2/docker/payments-logger/backend/.dockerignore\n/volume2/docker/payments-logger/backend/package.json\n/volume2/docker/payments-logger/backend/prisma/schema.prisma\n/volume2/docker/payments-logger/backend/src/parser.js\n/volume2/docker/payments-logger/backend/src/index.js\n/volume2/docker/payments-logger/backend/src/auth.js\n/volume2/docker/payments-logger/backend/prisma/migrations/migration_lock.toml\n/volume2/docker/payments-logger/backend/src/routes/payments.js\n/volume2/docker/payments-logger/backend/prisma/migrations/20260210_init/migration.sql\n/volume2/docker/payments-logger/backend/prisma/migrations/20260210_simplify/migration.sql\n/volume2/docker/payments-logger/backend/prisma/migrations/20260222_add_card/migration.sql","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"find /volume2/docker/payments-logger -type f \\( -name \"*.js\" -o -name \"*.json\" -o -name \"*.md\" \\) | sort","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/volume2/docker/payments-logger/API.md\n/volume2/docker/payments-logger/backend/package.json\n/volume2/docker/payments-logger/backend/src/auth.js\n/volume2/docker/payments-logger/backend/src/index.js\n/volume2/docker/payments-logger/backend/src/parser.js\n/volume2/docker/payments-logger/backend/src/routes/payments.js\n/volume2/docker/payments-logger/.claude/settings.local.json\n/volume2/docker/payments-logger/frontend/package.json\n/volume2/docker/payments-logger/frontend/postcss.config.js\n/volume2/docker/payments-logger/frontend/src/auth.js\n/volume2/docker/payments-logger/frontend/tailwind.config.js\n/volume2/docker/payments-logger/frontend/vite.config.js\n/volume2/docker/payments-logger/README.md","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":".env","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":".env","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"auth.js","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"auth.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"index.js","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"index.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"package.json","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"package.json","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"auth.js","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"auth.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"API.md","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"API.md","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"payments.js","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"payments.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":".env.example","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":".env.example","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"schema.prisma","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"schema.prisma","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"grep -r \"API_KEY\\|auth\\|token\\|oauth\\|hydra\" /volume2/docker/payments-logger/backend/src --include=\"*.js\" -n","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/volume2/docker/payments-logger/backend/src/index.js:6:const { bearerTokenMiddleware, wellKnownRouter } = require('./auth');\n/volume2/docker/payments-logger/backend/src/index.js:18:// ── OAuth Bearer token auth (skips public paths) ──────────────────────────────\n/volume2/docker/payments-logger/backend/src/auth.js:2: * OAuth 2.1 / Hydra JWT authentication for Express.\n/volume2/docker/payments-logger/backend/src/auth.js:6: * - wellKnownRouter — serves /.well-known/oauth-* discovery endpoints\n/volume2/docker/payments-logger/backend/src/auth.js:33:function sendUnauthorized(res, detail, error = 'invalid_token') {\n/volume2/docker/payments-logger/backend/src/auth.js:39: `resource_metadata=\"${realm}/.well-known/oauth-protected-resource\"`,\n/volume2/docker/payments-logger/backend/src/auth.js:40: `authorization_server=\"${HYDRA_PUBLIC_URL}\"`,\n/volume2/docker/payments-logger/backend/src/auth.js:52: * On success, attaches the decoded payload to req.tokenPayload.\n/volume2/docker/payments-logger/backend/src/auth.js:54: * @param {Set<string>} publicPaths Paths to skip auth for.\n/volume2/docker/payments-logger/backend/src/auth.js:58: '/.well-known/oauth-protected-resource',\n/volume2/docker/payments-logger/backend/src/auth.js:59: '/.well-known/oauth-authorization-server',\n/volume2/docker/payments-logger/backend/src/auth.js:66: const auth = req.headers.authorization || '';\n/volume2/docker/payments-logger/backend/src/auth.js:67: if (!auth.toLowerCase().startsWith('bearer ')) {\n/volume2/docker/payments-logger/backend/src/auth.js:68: return sendUnauthorized(res, 'Bearer token required', 'invalid_request');\n/volume2/docker/payments-logger/backend/src/auth.js:71: const token = auth.slice(7).trim();\n/volume2/docker/payments-logger/backend/src/auth.js:72: if (!token) {\n/volume2/docker/payments-logger/backend/src/auth.js:73: return sendUnauthorized(res, 'Bearer token required', 'invalid_request');\n/volume2/docker/payments-logger/backend/src/auth.js:82: const { payload } = await jwtVerify(token, getJwks(), verifyOptions);\n/volume2/docker/payments-logger/backend/src/auth.js:83: req.tokenPayload = payload;\n/volume2/docker/payments-logger/backend/src/auth.js:87: const error = msg.includes('expired') ? 'invalid_token' : 'invalid_token';\n/volume2/docker/payments-logger/backend/src/auth.js:88: sendUnauthorized(res, msg, error);\n/volume2/docker/payments-logger/backend/src/auth.js:98:wellKnownRouter.get('/.well-known/oauth-protected-resource', (_req, res) => {\n/volume2/docker/payments-logger/backend/src/auth.js:103: authorization_servers: [HYDRA_PUBLIC_URL],\n/volume2/docker/payments-logger/backend/src/auth.js:111:wellKnownRouter.get('/.well-known/oauth-authorization-server', async (_req, res) => {\n/volume2/docker/payments-logger/backend/src/auth.js:119: authorization_endpoint: doc.authorization_endpoint,\n/volume2/docker/payments-logger/backend/src/auth.js:120: token_endpoint: doc.token_endpoint,\n/volume2/docker/payments-logger/backend/src/auth.js:123: grant_types_supported: doc.grant_types_supported || ['authorization_code', 'refresh_token'],\n/volume2/docker/payments-logger/backend/src/auth.js:124: token_endpoint_auth_methods_supported: doc.token_endpoint_auth_methods_supported || ['none', 'client_secret_basic'],\n/volume2/docker/payments-logger/backend/src/auth.js:128: id_token_signing_alg_values_supported: doc.id_token_signing_alg_values_supported || ['RS256'],\n/volume2/docker/payments-logger/backend/src/routes/payments.js:58:// ── Ingest a payment (public — no auth) ──────────────────────────────────────","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"find /volume2/docker/payments-logger/frontend/src -type f -name \"*.js\" -o -name \"*.jsx\" -o -name \"*.ts\" -o -name \"*.tsx\" | head -20","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/volume2/docker/payments-logger/frontend/src/main.jsx\n/volume2/docker/payments-logger/frontend/src/App.jsx\n/volume2/docker/payments-logger/frontend/src/auth.js\n/volume2/docker/payments-logger/frontend/src/components/PaymentCard.jsx\n/volume2/docker/payments-logger/frontend/src/components/PaymentList.jsx\n/volume2/docker/payments-logger/frontend/src/components/FilterBar.jsx\n/volume2/docker/payments-logger/frontend/src/components/PaymentTable.jsx\n/volume2/docker/payments-logger/frontend/src/components/AuthProvider.jsx\n/volume2/docker/payments-logger/frontend/src/components/AuthCallback.jsx","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"AuthProvider.jsx","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"AuthProvider.jsx","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"AuthCallback.jsx","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"AuthCallback.jsx","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"App.jsx","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"App.jsx","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"main.jsx","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"main.jsx","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"vite.config.js","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"vite.config.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"grep -r \"HYDRA\\|VITE\" /volume2/docker/payments-logger --include=\".env*\" -n","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"(Bash completed with no output)","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"docker-compose.yml","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"docker-compose.yml","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"grep -r \"API_KEY\" /volume2/docker/payments-logger/backend --include=\"*.js\" -n","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"(Bash completed with no output)","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"README.md","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"README.md","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"grep -n \"HYDRA\\|oauth\\|TOKEN\" /volume2/docker/payments-logger/backend/src/index.js /volume2/docker/payments-logger/backend/src/auth.js | head -40","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/volume2/docker/payments-logger/backend/src/auth.js:6: * - wellKnownRouter — serves /.well-known/oauth-* discovery endpoints\n/volume2/docker/payments-logger/backend/src/auth.js:11:const HYDRA_PUBLIC_URL = (process.env.HYDRA_PUBLIC_URL || '').replace(/\\/$/, '');\n/volume2/docker/payments-logger/backend/src/auth.js:24: new URL(`${HYDRA_PUBLIC_URL}/.well-known/jwks.json`)\n/volume2/docker/payments-logger/backend/src/auth.js:39: `resource_metadata=\"${realm}/.well-known/oauth-protected-resource\"`,\n/volume2/docker/payments-logger/backend/src/auth.js:40: `authorization_server=\"${HYDRA_PUBLIC_URL}\"`,\n/volume2/docker/payments-logger/backend/src/auth.js:58: '/.well-known/oauth-protected-resource',\n/volume2/docker/payments-logger/backend/src/auth.js:59: '/.well-known/oauth-authorization-server',\n/volume2/docker/payments-logger/backend/src/auth.js:78: issuer: HYDRA_PUBLIC_URL,\n/volume2/docker/payments-logger/backend/src/auth.js:81: if (process.env.TOKEN_AUDIENCE) verifyOptions.audience = process.env.TOKEN_AUDIENCE;\n/volume2/docker/payments-logger/backend/src/auth.js:98:wellKnownRouter.get('/.well-known/oauth-protected-resource', (_req, res) => {\n/volume2/docker/payments-logger/backend/src/auth.js:103: authorization_servers: [HYDRA_PUBLIC_URL],\n/volume2/docker/payments-logger/backend/src/auth.js:107: jwks_uri: `${HYDRA_PUBLIC_URL}/.well-known/jwks.json`,\n/volume2/docker/payments-logger/backend/src/auth.js:111:wellKnownRouter.get('/.well-known/oauth-authorization-server', async (_req, res) => {\n/volume2/docker/payments-logger/backend/src/auth.js:113: const r = await fetch(`${HYDRA_PUBLIC_URL}/.well-known/openid-configuration`);\n/volume2/docker/payments-logger/backend/src/auth.js:118: issuer: doc.issuer || HYDRA_PUBLIC_URL,","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":23,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Thinking","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"payments-logger Authorization Overview","depth":22,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"payments-logger Authorization Overview","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"The project uses","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"OAuth 2.1 with PKCE","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"via an external Hydra OAuth server at","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"hydra.lakylak.xyz","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"Auth Flow","depth":22,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"Auth Flow","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Frontend","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"(","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"frontend/src/auth.js","depth":23,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"frontend/src/auth.js","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"):","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Fetches OAuth server metadata via discovery endpoint","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Generates a PKCE code verifier/challenge (SHA-256)","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Redirects user to Hydra login with","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"code_challenge","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"On callback, exchanges code + verifier for tokens","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Stores","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"access_token","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":",","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"refresh_token","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"in","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"localStorage","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"(","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"pl_oauth_tokens","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":")","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Auto-refreshes token 30 seconds before expiry","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Backend","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"(","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"backend/src/auth.js","depth":23,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"backend/src/auth.js","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"):","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"bearerTokenMiddleware","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"validates the","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Authorization: Bearer <token>","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"header","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Fetches Hydra's JWKS (cached 300s) and verifies JWT signature (RS256/ES256/PS256)","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Validates issuer (","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"https://hydra.lakylak.xyz","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":") and optional audience","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"Enforcement","depth":22,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"Enforcement","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Applied globally in","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"backend/src/index.js:19","depth":23,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"backend/src/index.js:19","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"with these","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"public (unprotected) paths","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":":","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/.well-known/oauth-protected-resource","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/.well-known/oauth-authorization-server","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/api/health","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/api/payments/ingest","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"(rate-limited at 200 req/min — for SMS ingestion)","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"Roles/Permissions","depth":22,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"Roles/Permissions","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"No RBAC","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"— it's binary: authenticated vs. unauthenticated. Required scopes:","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"openid","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":",","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"offline_access","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"Key Security Notes","depth":22,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"Key Security Notes","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PKCE","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"prevents authorization code interception","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"State parameter","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"provides CSRF protection","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"No server-side token storage","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"— validation is stateless via JWKS","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"The README/API docs mention an","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"X-API-Key","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"header, but that's","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"outdated","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"— the actual code uses Bearer tokens only","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Config lives in","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"docker-compose.yml","depth":23,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"docker-compose.yml","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"(lines 30–33):","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"HYDRA_PUBLIC_URL","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":",","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"REQUIRED_SCOPES","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":",","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"OAUTH_CLIENT_ID","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":", and optionally","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"TOKEN_AUDIENCE","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"JWKS_CACHE_TTL","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Message actions","depth":24,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"compare it to location logger and make it the same. Lets remove hydra and only use authentic (or whatever location logger uses).","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":23,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Thinking","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Let me first explore how location-logger handles authorization.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Agent:","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Explore location-logger authorization code","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Explore the location-logger project at /volume2/docker/location-logger and give me a thorough understanding of how authorization works. I need to know:\n\n1. What auth mechanism is used (JWT, sessions, API keys, OAuth, etc.)\n2. Where auth is enforced (middleware, decorators, route guards, etc.)\n3. What roles/permissions exist\n4. How tokens are issued, validated, and refreshed\n5. Any auth-related config (env vars, settings)\n6. Frontend auth flow (how the user logs in, how tokens are stored and used)\n7. The full directory/file structure of the project\n\nPlease read ALL relevant source files completely and give me a detailed summary with file paths and line numbers. I need enough detail to replicate this auth system in another project.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"find /volume2/docker/location-logger -type f -name \"*.py\" -o -name \"*.js\" -o -name \"*.ts\" -o -name \"*.json\" | head -50","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/volume2/docker/location-logger/.mcp.json\n/volume2/docker/location-logger/app/__init__.py\n/volume2/docker/location-logger/app/utils.py\n/volume2/docker/location-logger/app/config.py\n/volume2/docker/location-logger/app/main.py\n/volume2/docker/location-logger/alembic/env.py\n/volume2/docker/location-logger/mcp-server/server.py\n/volume2/docker/location-logger/alembic/versions/20260203_201500_create_location_points_table.py\n/volume2/docker/location-logger/alembic/versions/20260209_200000_add_enhanced_fields_and_tables.py\n/volume2/docker/location-logger/alembic/versions/20260214_000000_add_users_and_audit_logs.py\n/volume2/docker/location-logger/alembic/versions/20260320_000000_add_audit_query_string.py\n/volume2/docker/location-logger/app/services/geofence_service.py\n/volume2/docker/location-logger/app/services/recorder_service.py\n/volume2/docker/location-logger/app/services/trip_service.py\n/volume2/docker/location-logger/app/services/enhanced_location_service.py\n/volume2/docker/location-logger/app/services/geocoding_service.py\n/volume2/docker/location-logger/app/clients/__init__.py\n/volume2/docker/location-logger/app/clients/dawarich_client.py\n/volume2/docker/location-logger/app/clients/owntracks_client.py\n/volume2/docker/location-logger/app/models/areas.py\n/volume2/docker/location-logger/app/models/geofence_events.py\n/volume2/docker/location-logger/app/models/trips.py\n/volume2/docker/location-logger/app/models/user.py\n/volume2/docker/location-logger/app/models/location.py\n/volume2/docker/location-logger/app/models/audit_log.py\n/volume2/docker/location-logger/app/auth/__init__.py\n/volume2/docker/location-logger/app/auth/dependencies.py\n/volume2/docker/location-logger/app/auth/utils.py\n/volume2/docker/location-logger/app/api/enhanced_endpoints.py\n/volume2/docker/location-logger/app/db/base.py\n/volume2/docker/location-logger/app/db/session.py","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"tree -L 4 /volume2/docker/location-logger 2>/dev/null || find /volume2/docker/location-logger -type d | sort","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/volume2/docker/location-logger\n├── alembic\n│ ├── env.py\n│ ├── script.py.mako\n│ └── versions\n│ ├── 20260203_201500_create_location_points_table.py\n│ ├── 20260209_200000_add_enhanced_fields_and_tables.py\n│ ├── 20260214_000000_add_users_and_audit_logs.py\n│ ├── 20260320_000000_add_audit_query_string.py\n│ └── __pycache__\n│ └── 20260214_000000_add_users_and_audit_logs.cpython-311.pyc\n├── alembic.ini\n├── app\n│ ├── api\n│ │ └── enhanced_endpoints.py\n│ ├── auth\n│ │ ├── dependencies.py\n│ │ ├── __init__.py\n│ │ ├── __pycache__\n│ │ │ ├── dependencies.cpython-311.pyc\n│ │ │ ├── __init__.cpython-311.pyc\n│ │ │ └── utils.cpython-311.pyc\n│ │ └── utils.py\n│ ├── clients\n│ │ ├── dawarich_client.py\n│ │ ├── __init__.py\n│ │ └── owntracks_client.py\n│ ├── config.py\n│ ├── db\n│ │ ├── base.py\n│ │ └── session.py\n│ ├── __init__.py\n│ ├── main.py\n│ ├── models\n│ │ ├── areas.py\n│ │ ├── audit_log.py\n│ │ ├── geofence_events.py\n│ │ ├── location.py\n│ │ ├── __pycache__\n│ │ │ ├── audit_log.cpython-311.pyc\n│ │ │ └── user.cpython-311.pyc\n│ │ ├── trips.py\n│ │ └── user.py\n│ ├── __pycache__\n│ │ ├── __init__.cpython-311.pyc\n│ │ └── main.cpython-311.pyc\n│ ├── services\n│ │ ├── enhanced_location_service.py\n│ │ ├── geocoding_service.py\n│ │ ├── geofence_service.py\n│ │ ├── recorder_service.py\n│ │ └── trip_service.py\n│ ├── static\n│ │ └── dashboard.html\n│ └── utils.py\n├── docker-compose.yml\n├── Dockerfile\n├── mcp-server\n│ ├── Dockerfile\n│ ├── requirements.txt\n│ └── server.py\n├── README.md\n├── requirements.txt\n└── today_map.html\n\n16 directories, 48 files","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"utils.py","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"utils.py","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"dependencies.py","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"dependencies.py","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"user.py","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"user.py","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"config.py","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"config.py","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"main.py","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"main.py","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"session.py","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"session.py","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"dashboard.html","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"dashboard.html","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"audit_log.py","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"audit_log.py","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"20260214_000000_add_users_and_audit_logs.py","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"20260214_000000_add_users_and_audit_logs.py","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"20260320_000000_add_audit_query_string.py","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"20260320_000000_add_audit_query_string.py","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"README.md","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"README.md","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"requirements.txt","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"requirements.txt","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"server.py","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"server.py","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"server.py","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"server.py","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"(lines 101-400)","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":23,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Thinking","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Now I have a full picture of both systems. Let me read the payments-logger source files before planning the migration.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"List all payments-logger files","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"find /volume2/docker/payments-logger -type f | grep -v node_modules | grep -v .git | sort","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/volume2/docker/payments-logger/API.md\n/volume2/docker/payments-logger/backend/Dockerfile\n/volume2/docker/payments-logger/backend/.dockerignore\n/volume2/docker/payments-logger/backend/package.json\n/volume2/docker/payments-logger/backend/prisma/migrations/20260210_init/migration.sql\n/volume2/docker/payments-logger/backend/prisma/migrations/20260210_simplify/migration.sql\n/volume2/docker/payments-logger/backend/prisma/migrations/20260222_add_card/migration.sql\n/volume2/docker/payments-logger/backend/prisma/migrations/migration_lock.toml\n/volume2/docker/payments-logger/backend/prisma/schema.prisma\n/volume2/docker/payments-logger/backend/src/auth.js\n/volume2/docker/payments-logger/backend/src/index.js\n/volume2/docker/payments-logger/backend/src/parser.js\n/volume2/docker/payments-logger/backend/src/routes/payments.js\n/volume2/docker/payments-logger/.claude/settings.local.json\n/volume2/docker/payments-logger/docker-compose.yml\n/volume2/docker/payments-logger/.env\n/volume2/docker/payments-logger/.env.example\n/volume2/docker/payments-logger/frontend/Dockerfile\n/volume2/docker/payments-logger/frontend/.dockerignore\n/volume2/docker/payments-logger/frontend/index.html\n/volume2/docker/payments-logger/frontend/package.json\n/volume2/docker/payments-logger/frontend/postcss.config.js\n/volume2/docker/payments-logger/frontend/src/App.jsx\n/volume2/docker/payments-logger/frontend/src/auth.js\n/volume2/docker/payments-logger/frontend/src/components/AuthCallback.jsx\n/volume2/docker/payments-logger/frontend/src/components/AuthProvider.jsx\n/volume2/docker/payments-logger/frontend/src/components/FilterBar.jsx\n/volume2/docker/payments-logger/frontend/src/components/PaymentCard.jsx\n/volume2/docker/payments-logger/frontend/src/components/PaymentList.jsx\n/volume2/docker/payments-logger/frontend/src/components/PaymentTable.jsx\n/volume2/docker/payments-logger/frontend/src/index.css\n/volume2/docker/payments-logger/frontend/src/main.jsx\n/volume2/docker/payments-logger/frontend/tailwind.config.js\n/volume2/docker/payments-logger/frontend/vite.config.js\n/volume2/docker/payments-logger/README.md","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"auth.js","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"auth.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"index.js","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"index.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"auth.js","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"auth.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"AuthProvider.jsx","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"AuthProvider.jsx","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"package.json","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"package.json","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"AuthCallback.jsx","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"AuthCallback.jsx","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"schema.prisma","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"schema.prisma","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"docker-compose.yml","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"docker-compose.yml","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":23,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Thinking","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Now let me read the remaining frontend files.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"App.jsx","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"App.jsx","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"package.json","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"package.json","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":".env","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":".env","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":23,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Thinking","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Let me read the remaining files before making changes.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"main.jsx","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"main.jsx","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"vite.config.js","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"vite.config.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"payments.js","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"payments.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":23,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Thinking","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":".env.example","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":".env.example","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":23,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Thinking","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Now I have everything I need. Here's what changes:","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Backend:","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Rewrite","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"auth.js","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"(HS256 JWT + bcrypt), add","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/auth/login","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"+","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/auth/register","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"endpoints, add","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"User","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"model to Prisma, new migration, remove Hydra env vars.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Frontend:","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Replace PKCE flow with a simple login form in","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AuthProvider","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":", simplify","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"auth.js","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":", remove","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AuthCallback","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":", drop","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/.well-known","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"proxy.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Config:","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Drop all Hydra/OAuth env vars, add","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"JWT_SECRET","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Let me implement everything now.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Update Todos","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Add bcryptjs to backend package.json","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Rewrite backend/src/auth.js (HS256 JWT + bcrypt, login/register routes)","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Update backend/src/index.js (remove wellKnownRouter, mount authRouter)","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Add User model to prisma/schema.prisma","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Create Prisma migration for users table","depth":26,"on_screen":false,"role_description":"text"}]...
|
1157923603319689938
|
-4880851077058145720
|
click
|
accessibility
|
NULL
|
Explorer (⇧⌘E)
Search (⇧⌘F)
Source Control (⌃⇧ Explorer (⇧⌘E)
Search (⇧⌘F)
Source Control (⌃⇧G) - 55 pending changes
55
Run and Debug (⇧⌘D)
Remote Explorer
Extensions (⇧⌘X) - 2 require update
2
Claude Code
Containers
EXPLORER
EXPLORER
Explorer Section: docker [SSH: nas]
Explorer Section: docker [SSH: nas]
DOCKER [SSH: NAS]
audiobookshelf
auth
beszel
bitwarden
dawarich
dsk-uploader
flask-app
garmin-connector
gitea
health
health-tracker
homarr
hst
immich
jellyfinht
kavita
libreoffice
linkwarden
location-logger
alembic
app
mcp-server
.env
.env.example
.gitignore
.mcp.json
M
alembic.ini
docker-compose.yml
M
Dockerfile
README.md
M
requirements.txt
M
today_map.html
mariadb
meeting-detector
mindfulmama
n8n
notifier-app
npm
oauth
obsidian
ollama
open-webui
openttd
openvpn-client
orchestrator
outfit-app
owntracks-stack
paperlessngx
payments-logger
.claude
Outline Section
OUTLINE
OUTLINE
Timeline Section
TIMELINE
TIMELINE
docker-compose.yml, Editor Group 1
docker-compose.yml, Editor Group 1
Review payment logger au…, Editor Group 2
Problems (⇧⌘M)
PROBLEMS
Output (⇧⌘U)
OUTPUT
Debug Console (⇧⌘Y)
DEBUG CONSOLE
Terminal (⌃`)
TERMINAL
Ports
PORTS
remote SSH: nas
SSH: nas
location-logger (Git)
location-logger
location-logger (Git) - main*, Checkout Branch/Tag...
main*
location-logger (Git) - Synchronize Changes
No Problems
0
0
No Ports Forwarded
0
Notifications
Sign In
Sign In
collapsed
Clear
Review payment logger authorization implementation
Session history
New session
Message actions
review payment_logger project how toes authorization work
Thinking
Thinking
Let me explore the payment_logger project structure first.
Bash
Find payment_logger project files
IN
find /volume2/docker -type f -name "*.py" -o -name "*.yml" -o -name "*.yaml" -o -name "*.env" -o -name "*.toml" -o -name "*.cfg" | grep -i payment | head -50
Copy code to clipboard
OUT
bfs: error: /volume2/docker/portnotedb/pg_commit_ts: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_dynshmem: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_notify: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_serial: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_snapshots: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_subtrans: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_twophase: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_multixact: Permission denied.
bfs: error: /volume2/docker/portnotedb/base: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_replslot: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_tblspc: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_stat: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_stat_tmp: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_xact: Permission denied.
bfs: error: /volume2/docker/portnotedb/pg_logical: Permission denied.
bfs: error: /volume2/docker/openttd/.dbus: Permission denied.
bfs: error: /volume2/docker/immich/db: Permission denied.
bfs: error: /volume2/docker/paperlessngx/db: Permission denied.
bfs: error: /volume2/docker/appflowy/postgres: Permission denied.
bfs: error: /volume2/docker/auth/db: Permission denied.
bfs: error: /volume2/docker/openttd/.XDG/dbus-1: Permission denied.
bfs: error: /volume2/docker/openttd/.config/pulse: Permission denied.
bfs: error: /volume2/docker/openttd/.cache/openbox/sessions: Permission denied.
/volume2/docker/payments-logger/.env
/volume2/docker/payments-logger/docker-compose.yml
/volume2/docker/payments-logger/backend/prisma/migrations/migration_lock.toml
Bash
List docker directory contents
IN
ls /volume2/docker/
Copy code to clipboard
OUT
adguard
ai-stack
app-db
appflowy
audiobookshelf
auth
beszel
bitwarden
dawarich
dsk-uploader
flask-app
garmin-connector
gitea
health
health-tracker
homarr
hst
immich
jellyfinht
kavita
libreoffice
linkwarden
location-logger
mariadb
meeting-detector
mindfulmama
n8n
notifier-app
npm
oauth
obsidian
ollama
openttd
openvpn-client
open-webui
orchestrator
outfit-app
owntracks-stack
paperlessngx
payments-logger
personal-log
personal-log-system
player
portainer
portnotedb
reminders-app
romm
second-brain
static
stirling
syncthing
tailscale
temp-logger
test-app
tmp
torrent-stack
tree
trilium
tubearchivist
twenty
uptimekuma
ytptube
Agent:
Explore payment_logger authorization code
IN
Explore the payments-logger project at /volume2/docker/payments-logger and give me a thorough understanding of how authorization works. I need to know:
1. What auth mechanism is used (JWT, sessions, API keys, OAuth, etc.)
2. Where auth is enforced (middleware, decorators, route guards, etc.)
3. What roles/permissions exist
4. How tokens are issued, validated, and refreshed
5. Any auth-related config (env vars, settings)
Please read the key source files and give me a clear summary with file paths and line numbers for the important parts.
Bash
IN
find /volume2/docker/payments-logger -type f -name "*.py" -o -name "*.json" -o -name "*.yml" -o -name "*.yaml" | grep -E "(auth|token|jwt|session|permission|role)" | head -20
Copy code to clipboard
OUT
(Bash completed with no output)
Bash
IN
ls -la /volume2/docker/payments-logger/ 2>/dev/null || echo "Directory not found"
Copy code to clipboard
OUT
total 36
drwxrwxrwx 1 Adm1n admin 162 Mar 29 18:01 .
drwxrwxrwx 1 root root 1146 Apr 26 18:49 ..
-rwxrwxrwx 1 Adm1n admin 15233 Feb 22 17:08 API.md
drwxrwxrwx 1 Adm1n admin 88 Mar 29 15:41 backend
drwxrwxrwx 1 Adm1n admin 38 Mar 29 17:07 .claude
-rwxrwxrwx 1 Adm1n admin 1502 Mar 29 18:01 docker-compose.yml
-rwxrwxrwx 1 Adm1n admin 1066 Mar 29 15:44 .env
-rwxrwxrwx 1 Adm1n admin 1078 Feb 14 17:53 .env.example
drwxrwxrwx 1 Adm1n admin 194 Mar 29 15:44 frontend
-rwxrwxrwx 1 Adm1n admin 19 Feb 14 17:54 .gitignore
-rwxrwxrwx 1 Adm1n admin 4052 Feb 14 19:06 README.md
Bash
IN
find /volume2/docker/payments-logger/backend -type f | head -30
Copy code to clipboard
OUT
/volume2/docker/payments-logger/backend/Dockerfile
/volume2/docker/payments-logger/backend/.dockerignore
/volume2/docker/payments-logger/backend/package.json
/volume2/docker/payments-logger/backend/prisma/schema.prisma
/volume2/docker/payments-logger/backend/src/parser.js
/volume2/docker/payments-logger/backend/src/index.js
/volume2/docker/payments-logger/backend/src/auth.js
/volume2/docker/payments-logger/backend/prisma/migrations/migration_lock.toml
/volume2/docker/payments-logger/backend/src/routes/payments.js
/volume2/docker/payments-logger/backend/prisma/migrations/20260210_init/migration.sql
/volume2/docker/payments-logger/backend/prisma/migrations/20260210_simplify/migration.sql
/volume2/docker/payments-logger/backend/prisma/migrations/20260222_add_card/migration.sql
Bash
IN
find /volume2/docker/payments-logger -type f \( -name "*.js" -o -name "*.json" -o -name "*.md" \) | sort
Copy code to clipboard
OUT
/volume2/docker/payments-logger/API.md
/volume2/docker/payments-logger/backend/package.json
/volume2/docker/payments-logger/backend/src/auth.js
/volume2/docker/payments-logger/backend/src/index.js
/volume2/docker/payments-logger/backend/src/parser.js
/volume2/docker/payments-logger/backend/src/routes/payments.js
/volume2/docker/payments-logger/.claude/settings.local.json
/volume2/docker/payments-logger/frontend/package.json
/volume2/docker/payments-logger/frontend/postcss.config.js
/volume2/docker/payments-logger/frontend/src/auth.js
/volume2/docker/payments-logger/frontend/tailwind.config.js
/volume2/docker/payments-logger/frontend/vite.config.js
/volume2/docker/payments-logger/README.md
Read
.env
.env
Read
auth.js
auth.js
Read
index.js
index.js
Read
package.json
package.json
Read
auth.js
auth.js
Read
API.md
API.md
Read
payments.js
payments.js
Read
.env.example
.env.example
Read
schema.prisma
schema.prisma
Bash
IN
grep -r "API_KEY\|auth\|token\|oauth\|hydra" /volume2/docker/payments-logger/backend/src --include="*.js" -n
Copy code to clipboard
OUT
/volume2/docker/payments-logger/backend/src/index.js:6:const { bearerTokenMiddleware, wellKnownRouter } = require('./auth');
/volume2/docker/payments-logger/backend/src/index.js:18:// ── OAuth Bearer token auth (skips public paths) ──────────────────────────────
/volume2/docker/payments-logger/backend/src/auth.js:2: * OAuth 2.1 / Hydra JWT authentication for Express.
/volume2/docker/payments-logger/backend/src/auth.js:6: * - wellKnownRouter — serves /.well-known/oauth-* discovery endpoints
/volume2/docker/payments-logger/backend/src/auth.js:33:function sendUnauthorized(res, detail, error = 'invalid_token') {
/volume2/docker/payments-logger/backend/src/auth.js:39: `resource_metadata="${realm}/.well-known/oauth-protected-resource"`,
/volume2/docker/payments-logger/backend/src/auth.js:40: `authorization_server="${HYDRA_PUBLIC_URL}"`,
/volume2/docker/payments-logger/backend/src/auth.js:52: * On success, attaches the decoded payload to req.tokenPayload.
/volume2/docker/payments-logger/backend/src/auth.js:54: * @param {Set<string>} publicPaths Paths to skip auth for.
/volume2/docker/payments-logger/backend/src/auth.js:58: '/.well-known/oauth-protected-resource',
/volume2/docker/payments-logger/backend/src/auth.js:59: '/.well-known/oauth-authorization-server',
/volume2/docker/payments-logger/backend/src/auth.js:66: const auth = req.headers.authorization || '';
/volume2/docker/payments-logger/backend/src/auth.js:67: if (!auth.toLowerCase().startsWith('bearer ')) {
/volume2/docker/payments-logger/backend/src/auth.js:68: return sendUnauthorized(res, 'Bearer token required', 'invalid_request');
/volume2/docker/payments-logger/backend/src/auth.js:71: const token = auth.slice(7).trim();
/volume2/docker/payments-logger/backend/src/auth.js:72: if (!token) {
/volume2/docker/payments-logger/backend/src/auth.js:73: return sendUnauthorized(res, 'Bearer token required', 'invalid_request');
/volume2/docker/payments-logger/backend/src/auth.js:82: const { payload } = await jwtVerify(token, getJwks(), verifyOptions);
/volume2/docker/payments-logger/backend/src/auth.js:83: req.tokenPayload = payload;
/volume2/docker/payments-logger/backend/src/auth.js:87: const error = msg.includes('expired') ? 'invalid_token' : 'invalid_token';
/volume2/docker/payments-logger/backend/src/auth.js:88: sendUnauthorized(res, msg, error);
/volume2/docker/payments-logger/backend/src/auth.js:98:wellKnownRouter.get('/.well-known/oauth-protected-resource', (_req, res) => {
/volume2/docker/payments-logger/backend/src/auth.js:103: authorization_servers: [HYDRA_PUBLIC_URL],
/volume2/docker/payments-logger/backend/src/auth.js:111:wellKnownRouter.get('/.well-known/oauth-authorization-server', async (_req, res) => {
/volume2/docker/payments-logger/backend/src/auth.js:119: authorization_endpoint: doc.authorization_endpoint,
/volume2/docker/payments-logger/backend/src/auth.js:120: token_endpoint: doc.token_endpoint,
/volume2/docker/payments-logger/backend/src/auth.js:123: grant_types_supported: doc.grant_types_supported || ['authorization_code', 'refresh_token'],
/volume2/docker/payments-logger/backend/src/auth.js:124: [API_KEY]: doc.[API_KEY] || ['none', 'client_secret_basic'],
/volume2/docker/payments-logger/backend/src/auth.js:128: id_token_signing_alg_values_supported: doc.id_token_signing_alg_values_supported || ['RS256'],
/volume2/docker/payments-logger/backend/src/routes/payments.js:58:// ── Ingest a payment (public — no auth) ──────────────────────────────────────
Bash
IN
find /volume2/docker/payments-logger/frontend/src -type f -name "*.js" -o -name "*.jsx" -o -name "*.ts" -o -name "*.tsx" | head -20
Copy code to clipboard
OUT
/volume2/docker/payments-logger/frontend/src/main.jsx
/volume2/docker/payments-logger/frontend/src/App.jsx
/volume2/docker/payments-logger/frontend/src/auth.js
/volume2/docker/payments-logger/frontend/src/components/PaymentCard.jsx
/volume2/docker/payments-logger/frontend/src/components/PaymentList.jsx
/volume2/docker/payments-logger/frontend/src/components/FilterBar.jsx
/volume2/docker/payments-logger/frontend/src/components/PaymentTable.jsx
/volume2/docker/payments-logger/frontend/src/components/AuthProvider.jsx
/volume2/docker/payments-logger/frontend/src/components/AuthCallback.jsx
Read
AuthProvider.jsx
AuthProvider.jsx
Read
AuthCallback.jsx
AuthCallback.jsx
Read
App.jsx
App.jsx
Read
main.jsx
main.jsx
Read
vite.config.js
vite.config.js
Bash
IN
grep -r "HYDRA\|VITE" /volume2/docker/payments-logger --include=".env*" -n
Copy code to clipboard
OUT
(Bash completed with no output)
Read
docker-compose.yml
docker-compose.yml
Bash
IN
grep -r "API_KEY" /volume2/docker/payments-logger/backend --include="*.js" -n
Copy code to clipboard
OUT
(Bash completed with no output)
Read
README.md
README.md
Bash
IN
grep -n "HYDRA\|oauth\|TOKEN" /volume2/docker/payments-logger/backend/src/index.js /volume2/docker/payments-logger/backend/src/auth.js | head -40
Copy code to clipboard
OUT
/volume2/docker/payments-logger/backend/src/auth.js:6: * - wellKnownRouter — serves /.well-known/oauth-* discovery endpoints
/volume2/docker/payments-logger/backend/src/auth.js:11:const HYDRA_PUBLIC_URL = (process.env.HYDRA_PUBLIC_URL || '').replace(/\/$/, '');
/volume2/docker/payments-logger/backend/src/auth.js:24: new URL(`${HYDRA_PUBLIC_URL}/.well-known/jwks.json`)
/volume2/docker/payments-logger/backend/src/auth.js:39: `resource_metadata="${realm}/.well-known/oauth-protected-resource"`,
/volume2/docker/payments-logger/backend/src/auth.js:40: `authorization_server="${HYDRA_PUBLIC_URL}"`,
/volume2/docker/payments-logger/backend/src/auth.js:58: '/.well-known/oauth-protected-resource',
/volume2/docker/payments-logger/backend/src/auth.js:59: '/.well-known/oauth-authorization-server',
/volume2/docker/payments-logger/backend/src/auth.js:78: issuer: HYDRA_PUBLIC_URL,
/volume2/docker/payments-logger/backend/src/auth.js:81: if (process.env.TOKEN_AUDIENCE) verifyOptions.audience = process.env.TOKEN_AUDIENCE;
/volume2/docker/payments-logger/backend/src/auth.js:98:wellKnownRouter.get('/.well-known/oauth-protected-resource', (_req, res) => {
/volume2/docker/payments-logger/backend/src/auth.js:103: authorization_servers: [HYDRA_PUBLIC_URL],
/volume2/docker/payments-logger/backend/src/auth.js:107: jwks_uri: `${HYDRA_PUBLIC_URL}/.well-known/jwks.json`,
/volume2/docker/payments-logger/backend/src/auth.js:111:wellKnownRouter.get('/.well-known/oauth-authorization-server', async (_req, res) => {
/volume2/docker/payments-logger/backend/src/auth.js:113: const r = await fetch(`${HYDRA_PUBLIC_URL}/.well-known/openid-configuration`);
/volume2/docker/payments-logger/backend/src/auth.js:118: issuer: doc.issuer || HYDRA_PUBLIC_URL,
Thinking
Thinking
payments-logger Authorization Overview
payments-logger Authorization Overview
The project uses
OAuth 2.1 with PKCE
via an external Hydra OAuth server at
hydra.lakylak.xyz
.
Auth Flow
Auth Flow
Frontend
(
frontend/src/auth.js
frontend/src/auth.js
):
Fetches OAuth server metadata via discovery endpoint
Generates a PKCE code verifier/challenge (SHA-256)
Redirects user to Hydra login with
code_challenge
On callback, exchanges code + verifier for tokens
Stores
access_token
,
refresh_token
in
localStorage
(
pl_oauth_tokens
)
Auto-refreshes token 30 seconds before expiry
Backend
(
backend/src/auth.js
backend/src/auth.js
):
bearerTokenMiddleware
validates the
Authorization: Bearer <token>
header
Fetches Hydra's JWKS (cached 300s) and verifies JWT signature (RS256/ES256/PS256)
Validates issuer (
https://hydra.lakylak.xyz
) and optional audience
Enforcement
Enforcement
Applied globally in
backend/src/index.js:19
backend/src/index.js:19
with these
public (unprotected) paths
:
/.well-known/oauth-protected-resource
/.well-known/oauth-authorization-server
/api/health
/api/payments/ingest
(rate-limited at 200 req/min — for SMS ingestion)
Roles/Permissions
Roles/Permissions
No RBAC
— it's binary: authenticated vs. unauthenticated. Required scopes:
openid
,
offline_access
.
Key Security Notes
Key Security Notes
PKCE
prevents authorization code interception
State parameter
provides CSRF protection
No server-side token storage
— validation is stateless via JWKS
The README/API docs mention an
X-API-Key
header, but that's
outdated
— the actual code uses Bearer tokens only
Config lives in
docker-compose.yml
docker-compose.yml
(lines 30–33):
HYDRA_PUBLIC_URL
,
REQUIRED_SCOPES
,
OAUTH_CLIENT_ID
, and optionally
TOKEN_AUDIENCE
/
JWKS_CACHE_TTL
.
Message actions
compare it to location logger and make it the same. Lets remove hydra and only use authentic (or whatever location logger uses).
Thinking
Thinking
Let me first explore how location-logger handles authorization.
Agent:
Explore location-logger authorization code
IN
Explore the location-logger project at /volume2/docker/location-logger and give me a thorough understanding of how authorization works. I need to know:
1. What auth mechanism is used (JWT, sessions, API keys, OAuth, etc.)
2. Where auth is enforced (middleware, decorators, route guards, etc.)
3. What roles/permissions exist
4. How tokens are issued, validated, and refreshed
5. Any auth-related config (env vars, settings)
6. Frontend auth flow (how the user logs in, how tokens are stored and used)
7. The full directory/file structure of the project
Please read ALL relevant source files completely and give me a detailed summary with file paths and line numbers. I need enough detail to replicate this auth system in another project.
Bash
IN
find /volume2/docker/location-logger -type f -name "*.py" -o -name "*.js" -o -name "*.ts" -o -name "*.json" | head -50
Copy code to clipboard
OUT
/volume2/docker/location-logger/.mcp.json
/volume2/docker/location-logger/app/__init__.py
/volume2/docker/location-logger/app/utils.py
/volume2/docker/location-logger/app/config.py
/volume2/docker/location-logger/app/main.py
/volume2/docker/location-logger/alembic/env.py
/volume2/docker/location-logger/mcp-server/server.py
/volume2/docker/location-logger/alembic/versions/20260203_201500_create_location_points_table.py
/volume2/docker/location-logger/alembic/versions/20260209_200000_add_enhanced_fields_and_tables.py
/volume2/docker/location-logger/alembic/versions/20260214_000000_add_users_and_audit_logs.py
/volume2/docker/location-logger/alembic/versions/20260320_000000_add_audit_query_string.py
/volume2/docker/location-logger/app/services/geofence_service.py
/volume2/docker/location-logger/app/services/recorder_service.py
/volume2/docker/location-logger/app/services/trip_service.py
/volume2/docker/location-logger/app/services/enhanced_location_service.py
/volume2/docker/location-logger/app/services/geocoding_service.py
/volume2/docker/location-logger/app/clients/__init__.py
/volume2/docker/location-logger/app/clients/dawarich_client.py
/volume2/docker/location-logger/app/clients/owntracks_client.py
/volume2/docker/location-logger/app/models/areas.py
/volume2/docker/location-logger/app/models/geofence_events.py
/volume2/docker/location-logger/app/models/trips.py
/volume2/docker/location-logger/app/models/user.py
/volume2/docker/location-logger/app/models/location.py
/volume2/docker/location-logger/app/models/audit_log.py
/volume2/docker/location-logger/app/auth/__init__.py
/volume2/docker/location-logger/app/auth/dependencies.py
/volume2/docker/location-logger/app/auth/utils.py
/volume2/docker/location-logger/app/api/enhanced_endpoints.py
/volume2/docker/location-logger/app/db/base.py
/volume2/docker/location-logger/app/db/session.py
Bash
IN
tree -L 4 /volume2/docker/location-logger 2>/dev/null || find /volume2/docker/location-logger -type d | sort
Copy code to clipboard
OUT
/volume2/docker/location-logger
├── alembic
│ ├── env.py
│ ├── script.py.mako
│ └── versions
│ ├── 20260203_201500_create_location_points_table.py
│ ├── 20260209_200000_add_enhanced_fields_and_tables.py
│ ├── 20260214_000000_add_users_and_audit_logs.py
│ ├── 20260320_000000_add_audit_query_string.py
│ └── __pycache__
│ └── 20260214_000000_add_users_and_audit_logs.cpython-311.pyc
├── alembic.ini
├── app
│ ├── api
│ │ └── enhanced_endpoints.py
│ ├── auth
│ │ ├── dependencies.py
│ │ ├── __init__.py
│ │ ├── __pycache__
│ │ │ ├── dependencies.cpython-311.pyc
│ │ │ ├── __init__.cpython-311.pyc
│ │ │ └── utils.cpython-311.pyc
│ │ └── utils.py
│ ├── clients
│ │ ├── dawarich_client.py
│ │ ├── __init__.py
│ │ └── owntracks_client.py
│ ├── config.py
│ ├── db
│ │ ├── base.py
│ │ └── session.py
│ ├── __init__.py
│ ├── main.py
│ ├── models
│ │ ├── areas.py
│ │ ├── audit_log.py
│ │ ├── geofence_events.py
│ │ ├── location.py
│ │ ├── __pycache__
│ │ │ ├── audit_log.cpython-311.pyc
│ │ │ └── user.cpython-311.pyc
│ │ ├── trips.py
│ │ └── user.py
│ ├── __pycache__
│ │ ├── __init__.cpython-311.pyc
│ │ └── main.cpython-311.pyc
│ ├── services
│ │ ├── enhanced_location_service.py
│ │ ├── geocoding_service.py
│ │ ├── geofence_service.py
│ │ ├── recorder_service.py
│ │ └── trip_service.py
│ ├── static
│ │ └── dashboard.html
│ └── utils.py
├── docker-compose.yml
├── Dockerfile
├── mcp-server
│ ├── Dockerfile
│ ├── requirements.txt
│ └── server.py
├── README.md
├── requirements.txt
└── today_map.html
16 directories, 48 files
Read
utils.py
utils.py
Read
dependencies.py
dependencies.py
Read
user.py
user.py
Read
config.py
config.py
Read
main.py
main.py
Read
session.py
session.py
Read
dashboard.html
dashboard.html
Read
audit_log.py
audit_log.py
Read
20260214_000000_add_users_and_audit_logs.py
20260214_000000_add_users_and_audit_logs.py
Read
20260320_000000_add_audit_query_string.py
20260320_000000_add_audit_query_string.py
Read
README.md
README.md
Read
requirements.txt
requirements.txt
Read
server.py
server.py
Read
server.py
server.py
(lines 101-400)
Thinking
Thinking
Now I have a full picture of both systems. Let me read the payments-logger source files before planning the migration.
Bash
List all payments-logger files
IN
find /volume2/docker/payments-logger -type f | grep -v node_modules | grep -v .git | sort
Copy code to clipboard
OUT
/volume2/docker/payments-logger/API.md
/volume2/docker/payments-logger/backend/Dockerfile
/volume2/docker/payments-logger/backend/.dockerignore
/volume2/docker/payments-logger/backend/package.json
/volume2/docker/payments-logger/backend/prisma/migrations/20260210_init/migration.sql
/volume2/docker/payments-logger/backend/prisma/migrations/20260210_simplify/migration.sql
/volume2/docker/payments-logger/backend/prisma/migrations/20260222_add_card/migration.sql
/volume2/docker/payments-logger/backend/prisma/migrations/migration_lock.toml
/volume2/docker/payments-logger/backend/prisma/schema.prisma
/volume2/docker/payments-logger/backend/src/auth.js
/volume2/docker/payments-logger/backend/src/index.js
/volume2/docker/payments-logger/backend/src/parser.js
/volume2/docker/payments-logger/backend/src/routes/payments.js
/volume2/docker/payments-logger/.claude/settings.local.json
/volume2/docker/payments-logger/docker-compose.yml
/volume2/docker/payments-logger/.env
/volume2/docker/payments-logger/.env.example
/volume2/docker/payments-logger/frontend/Dockerfile
/volume2/docker/payments-logger/frontend/.dockerignore
/volume2/docker/payments-logger/frontend/index.html
/volume2/docker/payments-logger/frontend/package.json
/volume2/docker/payments-logger/frontend/postcss.config.js
/volume2/docker/payments-logger/frontend/src/App.jsx
/volume2/docker/payments-logger/frontend/src/auth.js
/volume2/docker/payments-logger/frontend/src/components/AuthCallback.jsx
/volume2/docker/payments-logger/frontend/src/components/AuthProvider.jsx
/volume2/docker/payments-logger/frontend/src/components/FilterBar.jsx
/volume2/docker/payments-logger/frontend/src/components/PaymentCard.jsx
/volume2/docker/payments-logger/frontend/src/components/PaymentList.jsx
/volume2/docker/payments-logger/frontend/src/components/PaymentTable.jsx
/volume2/docker/payments-logger/frontend/src/index.css
/volume2/docker/payments-logger/frontend/src/main.jsx
/volume2/docker/payments-logger/frontend/tailwind.config.js
/volume2/docker/payments-logger/frontend/vite.config.js
/volume2/docker/payments-logger/README.md
Read
auth.js
auth.js
Read
index.js
index.js
Read
auth.js
auth.js
Read
AuthProvider.jsx
AuthProvider.jsx
Read
package.json
package.json
Read
AuthCallback.jsx
AuthCallback.jsx
Read
schema.prisma
schema.prisma
Read
docker-compose.yml
docker-compose.yml
Thinking
Thinking
Now let me read the remaining frontend files.
Read
App.jsx
App.jsx
Read
package.json
package.json
Read
.env
.env
Thinking
Thinking
Let me read the remaining files before making changes.
Read
main.jsx
main.jsx
Read
vite.config.js
vite.config.js
Read
payments.js
payments.js
Thinking
Thinking
Read
.env.example
.env.example
Thinking
Thinking
Now I have everything I need. Here's what changes:
Backend:
Rewrite
auth.js
(HS256 JWT + bcrypt), add
/auth/login
+
/auth/register
endpoints, add
User
model to Prisma, new migration, remove Hydra env vars.
Frontend:
Replace PKCE flow with a simple login form in
AuthProvider
, simplify
auth.js
, remove
AuthCallback
, drop
/.well-known
proxy.
Config:
Drop all Hydra/OAuth env vars, add
JWT_SECRET
.
Let me implement everything now.
Update Todos
Add bcryptjs to backend package.json
Rewrite backend/src/auth.js (HS256 JWT + bcrypt, login/register routes)
Update backend/src/index.js (remove wellKnownRouter, mount authRouter)
Add User model to prisma/schema.prisma
Create Prisma migration for users table...
|
10650
|
NULL
|
NULL
|
NULL
|
|
11428
|
516
|
43
|
2026-05-08T19:16:48.125696+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778267808125_m2.jpg...
|
Firefox
|
Nginx Proxy Manager — Personal
|
True
|
http://192.168.0.242:81/nginx/proxy
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Pull requests · screenpipe/screenpipe · GitHub
Pul Pull requests · screenpipe/screenpipe · GitHub
Pull requests · screenpipe/screenpipe · GitHub
Nginx Proxy Manager
Nginx Proxy Manager
Close tab
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
AFFiNE - All In One KnowledgeOS
AFFiNE - All In One KnowledgeOS
All docs · AFFiNE
All docs · AFFiNE
Payments Logger
Payments Logger
[NirDiamant/GenAI_Agents] Add SwarmScore — Portable Trust Rating for AI Agents (Issue #115) - [EMAIL] - Gmail
[NirDiamant/GenAI_Agents] Add SwarmScore — Portable Trust Rating for AI Agents (Issue #115) - [EMAIL] - Gmail
New Tab
New Tab
Location Logger
Location Logger
Finance Hub
Finance Hub
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Nginx Proxy Manager
Nginx Proxy Manager
Admin Administrator
Admin
Administrator
Dashboard
Dashboard
Hosts
Hosts
Access Lists
Access Lists
SSL Certificates
SSL Certificates
Users
Users
Audit Log
Audit Log
Settings
Settings
Proxy Hosts
Proxy Hosts
Search Host…
Add Proxy Host
Add Proxy Host
SOURCE
DESTINATION
SSL
ACCESS
STATUS
ai.chat.lakylak.xyz
Created: 10th March 2026
http://[IP_ADDRESS]:11000
Let's Encrypt
Public
Online
app.lakylak.xyz
Created: 19th July 2025
http://[IP_ADDRESS]:18083
Let's Encrypt
Public
Online
app.payments.lakylak.xyz
Created: 14th February 2026
http://[IP_ADDRESS]:5174
Let's Encrypt
Public
Online
app.screenpipe.lakylak.xyz
Created: 27th April 2026
http://[IP_ADDRESS]:8766
Let's Encrypt
Public
Online
audiobook.lakylak.xyz
Created: 15th June 2025
http://192.168..242:13378
Let's Encrypt
Public
Online
auth.lakylak.xyz
Created: 30th March 2026
http://[IP_ADDRESS]:9100
Let's Encrypt
Public
Online
backup.lakylak.xyz
Created: 10th July 2025
http://[IP_ADDRESS]:9999
Let's Encrypt
Public
Online
beszel.lakylak.xyz
Created: 6th December 2025
http://[IP_ADDRESS]:8095
Let's Encrypt
Public
Online
bitwarden.lakylak.xyz
Created: 16th June 2025
http://[IP_ADDRESS]:9890
Let's Encrypt
Public
Online
book.lakylak.xyz
Created: 31st October 2025
http://[IP_ADDRESS]:6060
Let's Encrypt
Public
Online
crm.lakylak.xyz
Created: 25th July 2025
http://[IP_ADDRESS]:3353
Let's Encrypt
Public
Online
dawarich.lakylak.xyz
Created: 25th August 2025
http://[IP_ADDRESS]:3000
Let's Encrypt
Public
Online
db.screenpipe.lakylak.xyz
Created: 27th April 2026
http://[IP_ADDRESS]:8767
Let's Encrypt
Public
Online
dsk-uploader.lakylak.xyz
Created: 15th August 2025
http://[IP_ADDRESS]:8502
Let's Encrypt
Public
Online
gitea.lakylak.xyz
Created: 18th July 2025
http://[IP_ADDRESS]:3052
Let's Encrypt
Public
Online
hydra.lakylak.xyz
Created: 29th March 2026
http://[IP_ADDRESS]:4444
Let's Encrypt
Public
Online
images.lakylak.xyz
Created: 17th June 2025
http://[IP_ADDRESS]:3474
Let's Encrypt
Public
Online
immich.lakylak.xyz
Created: 15th June 2025
http://[IP_ADDRESS]:8212
Let's Encrypt
Public
Online
jellyfin.lakylak.xyz
Created: 15th June 2025
http://[IP_ADDRESS]:8096
Let's Encrypt
Public
Online
lakylak.xyz
Created: 15th June 2025
http://[IP_ADDRESS]:9999
Let's Encrypt
Public
Online
linkwarden.lakylak.xyz
Created: 13th December 2025
http://[IP_ADDRESS]:7461
Let's Encrypt
Public
Online
location-tracker.lakylak.xyz
Created: 30th August 2025
http://[IP_ADDRESS]:8050
Let's Encrypt
Public
Online
log.lakylak.xyz
Created: 23rd September 2025
http://[IP_ADDRESS]:18084
Let's Encrypt
Public
Online
login.lakylak.xyz
Created: 29th March 2026
http://[IP_ADDRESS]:4446
Let's Encrypt
Public
Online
mcp.location.lakylak.xyz
Created: 15th March 2026
http://[IP_ADDRESS]:8052
Let's Encrypt
Public
Online
n8n.lakylak.xyz
Created: 17th July 2025
http://[IP_ADDRESS]:5678
Let's Encrypt
Public
Online
nas.lakylak.xyz
Created: 28th July 2025
http://[IP_ADDRESS]:9999
Let's Encrypt
Public
Online
notes.lakylak.xyz
Created: 31st October 2025
http://[IP_ADDRESS]:8085
Let's Encrypt
Public
Online
obsidian.lakylak.xyz
Created: 17th June 2025
http://[IP_ADDRESS]:3421
Let's Encrypt
Public
Online
outfit.lakylak.xyz
Created: 25th March 2026
http://[IP_ADDRESS]:8667
Let's Encrypt
Public
Online
owntracks.lakylak.xyz
Created: 12th August 2025
http://[IP_ADDRESS]:8083
Let's Encrypt
Public
Online
paperless.lakylak.xyz
Created: 25th October 2025
http://[IP_ADDRESS]:8777
Let's Encrypt
Public
Online
payments.lakylak.xyz
Created: 14th February 2026
http://[IP_ADDRESS]:3010
Let's Encrypt
Public
Online
pdf.lakylak.xyz
Created: 19th June 2025
http://[IP_ADDRESS]:7890
Let's Encrypt
Public
Online
portainer.lakylak.xyz
Created: 15th June 2025
http://[IP_ADDRESS]:9000
Let's Encrypt
Public
Online
sqlite.screenpipe.lakylak.xyz
Created: 27th April 2026
http://[IP_ADDRESS]:8768
Let's Encrypt
Public
Online
todo.lakylak.xyz
Created: 16th March 2026
http://reminder-app:8000
Let's Encrypt
Public
Online
tree.lakylak.xyz
Created: 19th December 2025
http://[IP_ADDRESS]:8200
Let's Encrypt
Public
Online
trilium.lakylak.xyz
Created: 24th December 2025
http://[IP_ADDRESS]:4292
Let's Encrypt
Public
Online
tube.lakylak.xyz
Created: 3rd December 2025
http://[IP_ADDRESS]:8770
Let's Encrypt
Public
Online
ytber.lakylak.xyz
Created: 11th March 2026
http://[IP_ADDRESS]:8100
Let's Encrypt
Public
Online...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Pull requests · screenpipe/screenpipe · GitHub","depth":4,"bounds":{"left":0.0,"top":0.0518755,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests · screenpipe/screenpipe · GitHub","depth":5,"bounds":{"left":0.013297873,"top":0.06304868,"width":0.080784574,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Nginx Proxy Manager","depth":4,"bounds":{"left":0.0,"top":0.08459697,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Nginx Proxy Manager","depth":5,"bounds":{"left":0.013297873,"top":0.09577015,"width":0.036901597,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.10139628,"top":0.09177973,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Screenpipe — Archive","depth":4,"bounds":{"left":0.0,"top":0.11731844,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Screenpipe — Archive","depth":5,"bounds":{"left":0.013297873,"top":0.12849163,"width":0.037898935,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: archive.db","depth":4,"bounds":{"left":0.0,"top":0.15003991,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: archive.db","depth":5,"bounds":{"left":0.013297873,"top":0.16121309,"width":0.040724736,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: db.sqlite","depth":4,"bounds":{"left":0.0,"top":0.18276137,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: db.sqlite","depth":5,"bounds":{"left":0.013297873,"top":0.19393456,"width":0.03756649,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub","depth":4,"bounds":{"left":0.0,"top":0.21548285,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub","depth":5,"bounds":{"left":0.013297873,"top":0.22665602,"width":0.11469415,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"DXP4800PLUS-B5F8","depth":4,"bounds":{"left":0.0,"top":0.2482043,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"DXP4800PLUS-B5F8","depth":5,"bounds":{"left":0.013297873,"top":0.25937748,"width":0.036901597,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Оптичен интернет за дома - EON телевизия | Vivacom | 5G","depth":4,"bounds":{"left":0.0,"top":0.28092578,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Оптичен интернет за дома - EON телевизия | Vivacom | 5G","depth":5,"bounds":{"left":0.013297873,"top":0.29209897,"width":0.105884306,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"AFFiNE - All In One KnowledgeOS","depth":4,"bounds":{"left":0.0,"top":0.31364724,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AFFiNE - All In One KnowledgeOS","depth":5,"bounds":{"left":0.013297873,"top":0.32482043,"width":0.05851064,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"All docs · AFFiNE","depth":4,"bounds":{"left":0.0,"top":0.3463687,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"All docs · AFFiNE","depth":5,"bounds":{"left":0.013297873,"top":0.3575419,"width":0.029587766,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Payments Logger","depth":4,"bounds":{"left":0.0,"top":0.3790902,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Payments Logger","depth":5,"bounds":{"left":0.013297873,"top":0.39026338,"width":0.030086435,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[NirDiamant/GenAI_Agents] Add SwarmScore — Portable Trust Rating for AI Agents (Issue #115) - kovaliklukas@gmail.com - Gmail","depth":4,"bounds":{"left":0.0,"top":0.41181165,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[NirDiamant/GenAI_Agents] Add SwarmScore — Portable Trust Rating for AI Agents (Issue #115) - kovaliklukas@gmail.com - Gmail","depth":5,"bounds":{"left":0.013297873,"top":0.42298484,"width":0.22639628,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"New Tab","depth":4,"bounds":{"left":0.0,"top":0.4445331,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New Tab","depth":5,"bounds":{"left":0.013297873,"top":0.4557063,"width":0.014960106,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Location Logger","depth":4,"bounds":{"left":0.0,"top":0.4772546,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Location Logger","depth":5,"bounds":{"left":0.013297873,"top":0.4884278,"width":0.028091755,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Finance Hub","depth":4,"bounds":{"left":0.0,"top":0.509976,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Finance Hub","depth":5,"bounds":{"left":0.013297873,"top":0.5211492,"width":0.021609042,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.0028257978,"top":0.5442937,"width":0.108211435,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.0028257978,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"bounds":{"left":0.013796543,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.024933511,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.036070477,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bitwarden","depth":6,"bounds":{"left":0.04720745,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Nginx Proxy Manager","depth":8,"bounds":{"left":0.1512633,"top":0.061452515,"width":0.06665558,"height":0.03471668},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Nginx Proxy Manager","depth":9,"bounds":{"left":0.1619016,"top":0.06783719,"width":0.056017287,"height":0.018355945},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Admin Administrator","depth":8,"bounds":{"left":0.42021278,"top":0.06584198,"width":0.042220745,"height":0.02593775},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Admin","depth":10,"bounds":{"left":0.4375,"top":0.06424581,"width":0.013464096,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Administrator","depth":11,"bounds":{"left":0.4375,"top":0.07980846,"width":0.024933511,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":" Dashboard","depth":10,"bounds":{"left":0.1512633,"top":0.10654429,"width":0.028756648,"height":0.044293694},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":12,"bounds":{"left":0.1512633,"top":0.122505985,"width":0.004654255,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Dashboard","depth":11,"bounds":{"left":0.15724733,"top":0.12051077,"width":0.022772606,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":" Hosts","depth":10,"bounds":{"left":0.18799867,"top":0.10654429,"width":0.01761968,"height":0.044293694},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":12,"bounds":{"left":0.18799867,"top":0.122505985,"width":0.004654255,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Hosts","depth":11,"bounds":{"left":0.1939827,"top":0.12051077,"width":0.011635638,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":" Access Lists","depth":10,"bounds":{"left":0.21359707,"top":0.10654429,"width":0.030086435,"height":0.044293694},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":12,"bounds":{"left":0.21359707,"top":0.122505985,"width":0.004654255,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Access Lists","depth":11,"bounds":{"left":0.21958111,"top":0.12051077,"width":0.024102394,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":" SSL Certificates","depth":10,"bounds":{"left":0.25166222,"top":0.10654429,"width":0.038065158,"height":0.044293694},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":12,"bounds":{"left":0.25166222,"top":0.122505985,"width":0.004654255,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SSL Certificates","depth":11,"bounds":{"left":0.25764626,"top":0.12051077,"width":0.032081116,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":" Users","depth":10,"bounds":{"left":0.29770613,"top":0.10654429,"width":0.01761968,"height":0.044293694},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":12,"bounds":{"left":0.29770613,"top":0.122505985,"width":0.004654255,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Users","depth":11,"bounds":{"left":0.30369017,"top":0.12051077,"width":0.011635638,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":" Audit Log","depth":10,"bounds":{"left":0.32330453,"top":0.10654429,"width":0.025598405,"height":0.044293694},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":12,"bounds":{"left":0.32330453,"top":0.122505985,"width":0.004654255,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Audit Log","depth":11,"bounds":{"left":0.32928857,"top":0.12051077,"width":0.019614361,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":" Settings","depth":10,"bounds":{"left":0.35688165,"top":0.10654429,"width":0.022938829,"height":0.044293694},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":12,"bounds":{"left":0.35688165,"top":0.122505985,"width":0.004654255,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Settings","depth":11,"bounds":{"left":0.3628657,"top":0.12051077,"width":0.016954787,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Proxy Hosts","depth":9,"bounds":{"left":0.15957446,"top":0.1839585,"width":0.02925532,"height":0.017557861},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Proxy Hosts","depth":10,"bounds":{"left":0.15957446,"top":0.18355946,"width":0.02925532,"height":0.018355945},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"","depth":11,"bounds":{"left":0.3409242,"top":0.1867518,"width":0.004986702,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXTextField","text":"Search Host…","depth":10,"bounds":{"left":0.33676863,"top":0.18156424,"width":0.06898271,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"text field","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"","depth":9,"bounds":{"left":0.4084109,"top":0.18156424,"width":0.011303191,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":10,"bounds":{"left":0.4114029,"top":0.1867518,"width":0.005319149,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Add Proxy Host","depth":9,"bounds":{"left":0.42237368,"top":0.18156424,"width":0.034408245,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Add Proxy Host","depth":10,"bounds":{"left":0.4253657,"top":0.1859537,"width":0.028424202,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SOURCE","depth":12,"bounds":{"left":0.17819148,"top":0.22306465,"width":0.016289894,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"DESTINATION","depth":12,"bounds":{"left":0.25748006,"top":0.22306465,"width":0.02642952,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SSL","depth":12,"bounds":{"left":0.33743352,"top":0.22306465,"width":0.0071476065,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ACCESS","depth":12,"bounds":{"left":0.38131648,"top":0.22306465,"width":0.01512633,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"STATUS","depth":12,"bounds":{"left":0.41023937,"top":0.22306465,"width":0.014960106,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ai.chat.lakylak.xyz","depth":12,"bounds":{"left":0.18085106,"top":0.25897846,"width":0.030418882,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 10th March 2026","depth":13,"bounds":{"left":0.17819148,"top":0.28052673,"width":0.046043884,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:11000","depth":13,"bounds":{"left":0.25748006,"top":0.26735833,"width":0.055518616,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"bounds":{"left":0.33743352,"top":0.26735833,"width":0.026928192,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"bounds":{"left":0.38131648,"top":0.26735833,"width":0.013131649,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"bounds":{"left":0.41489363,"top":0.26735833,"width":0.014793883,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"bounds":{"left":0.44913563,"top":0.26735833,"width":0.004986702,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"bounds":{"left":0.44913563,"top":0.26855546,"width":0.004986702,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app.lakylak.xyz","depth":12,"bounds":{"left":0.18085106,"top":0.31843576,"width":0.025598405,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 19th July 2025","depth":13,"bounds":{"left":0.17819148,"top":0.33998403,"width":0.042386968,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:18083","depth":13,"bounds":{"left":0.25748006,"top":0.3272147,"width":0.055518616,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"bounds":{"left":0.33743352,"top":0.3272147,"width":0.026928192,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"bounds":{"left":0.38131648,"top":0.3272147,"width":0.013131649,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"bounds":{"left":0.41489363,"top":0.3272147,"width":0.014793883,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"bounds":{"left":0.44913563,"top":0.3272147,"width":0.004986702,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"bounds":{"left":0.44913563,"top":0.32841182,"width":0.004986702,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app.payments.lakylak.xyz","depth":12,"bounds":{"left":0.18085106,"top":0.37789306,"width":0.04305186,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 14th February 2026","depth":13,"bounds":{"left":0.17819148,"top":0.39944133,"width":0.05119681,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:5174","depth":13,"bounds":{"left":0.25748006,"top":0.386672,"width":0.053025264,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"bounds":{"left":0.33743352,"top":0.386672,"width":0.026928192,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"bounds":{"left":0.38131648,"top":0.386672,"width":0.013131649,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"bounds":{"left":0.41489363,"top":0.386672,"width":0.014793883,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"bounds":{"left":0.44913563,"top":0.386672,"width":0.004986702,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"bounds":{"left":0.44913563,"top":0.38786912,"width":0.004986702,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app.screenpipe.lakylak.xyz","depth":12,"bounds":{"left":0.18085106,"top":0.43774942,"width":0.04488032,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 27th April 2026","depth":13,"bounds":{"left":0.17819148,"top":0.4592977,"width":0.04338431,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:8766","depth":13,"bounds":{"left":0.25748006,"top":0.4461293,"width":0.053025264,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"bounds":{"left":0.33743352,"top":0.4461293,"width":0.026928192,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"bounds":{"left":0.38131648,"top":0.4461293,"width":0.013131649,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"bounds":{"left":0.41489363,"top":0.4461293,"width":0.014793883,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"bounds":{"left":0.44913563,"top":0.4461293,"width":0.004986702,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"bounds":{"left":0.44913563,"top":0.44732642,"width":0.004986702,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"audiobook.lakylak.xyz","depth":12,"bounds":{"left":0.18085106,"top":0.49720672,"width":0.03723404,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 15th June 2025","depth":13,"bounds":{"left":0.17819148,"top":0.51875496,"width":0.043882977,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168..242:13378","depth":13,"bounds":{"left":0.25748006,"top":0.5059856,"width":0.053025264,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"bounds":{"left":0.33743352,"top":0.5059856,"width":0.026928192,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"bounds":{"left":0.38131648,"top":0.5059856,"width":0.013131649,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"bounds":{"left":0.41489363,"top":0.5059856,"width":0.014793883,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"bounds":{"left":0.44913563,"top":0.5059856,"width":0.004986702,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"bounds":{"left":0.44913563,"top":0.5071828,"width":0.004986702,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"auth.lakylak.xyz","depth":12,"bounds":{"left":0.18085106,"top":0.556664,"width":0.026928192,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 30th March 2026","depth":13,"bounds":{"left":0.17819148,"top":0.5786113,"width":0.046043884,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:9100","depth":13,"bounds":{"left":0.25748006,"top":0.5654429,"width":0.053025264,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"bounds":{"left":0.33743352,"top":0.5654429,"width":0.026928192,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"bounds":{"left":0.38131648,"top":0.5654429,"width":0.013131649,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"bounds":{"left":0.41489363,"top":0.5654429,"width":0.014793883,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"bounds":{"left":0.44913563,"top":0.5654429,"width":0.004986702,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"bounds":{"left":0.44913563,"top":0.5666401,"width":0.004986702,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"backup.lakylak.xyz","depth":12,"bounds":{"left":0.18085106,"top":0.61652035,"width":0.031416222,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 10th July 2025","depth":13,"bounds":{"left":0.17819148,"top":0.6380686,"width":0.042386968,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.243:9999","depth":13,"bounds":{"left":0.25748006,"top":0.6249002,"width":0.053025264,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"bounds":{"left":0.33743352,"top":0.6249002,"width":0.026928192,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"bounds":{"left":0.38131648,"top":0.6249002,"width":0.013131649,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"bounds":{"left":0.41489363,"top":0.6249002,"width":0.014793883,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"bounds":{"left":0.44913563,"top":0.6249002,"width":0.004986702,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"bounds":{"left":0.44913563,"top":0.6260974,"width":0.004986702,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"beszel.lakylak.xyz","depth":12,"bounds":{"left":0.18085106,"top":0.67597765,"width":0.029587766,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 6th December 2025","depth":13,"bounds":{"left":0.17819148,"top":0.6975259,"width":0.05119681,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:8095","depth":13,"bounds":{"left":0.25748006,"top":0.6847566,"width":0.053025264,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"bounds":{"left":0.33743352,"top":0.6847566,"width":0.026928192,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"bounds":{"left":0.38131648,"top":0.6847566,"width":0.013131649,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"bounds":{"left":0.41489363,"top":0.6847566,"width":0.014793883,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"bounds":{"left":0.44913563,"top":0.6847566,"width":0.004986702,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"bounds":{"left":0.44913563,"top":0.68595374,"width":0.004986702,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"bitwarden.lakylak.xyz","depth":12,"bounds":{"left":0.18085106,"top":0.73543495,"width":0.036236703,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 16th June 2025","depth":13,"bounds":{"left":0.17819148,"top":0.7573823,"width":0.043882977,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:9890","depth":13,"bounds":{"left":0.25748006,"top":0.7442139,"width":0.053025264,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"bounds":{"left":0.33743352,"top":0.7442139,"width":0.026928192,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"bounds":{"left":0.38131648,"top":0.7442139,"width":0.013131649,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"bounds":{"left":0.41489363,"top":0.7442139,"width":0.014793883,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"bounds":{"left":0.44913563,"top":0.7442139,"width":0.004986702,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"bounds":{"left":0.44913563,"top":0.74541104,"width":0.004986702,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"book.lakylak.xyz","depth":12,"bounds":{"left":0.18085106,"top":0.7952913,"width":0.027759308,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 31st October 2025","depth":13,"bounds":{"left":0.17819148,"top":0.8168396,"width":0.04886968,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:6060","depth":13,"bounds":{"left":0.25748006,"top":0.8036712,"width":0.053025264,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"bounds":{"left":0.33743352,"top":0.8036712,"width":0.026928192,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"bounds":{"left":0.38131648,"top":0.8036712,"width":0.013131649,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"bounds":{"left":0.41489363,"top":0.8036712,"width":0.014793883,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"bounds":{"left":0.44913563,"top":0.8036712,"width":0.004986702,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"bounds":{"left":0.44913563,"top":0.80486834,"width":0.004986702,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"crm.lakylak.xyz","depth":12,"bounds":{"left":0.18085106,"top":0.8547486,"width":0.025598405,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 25th July 2025","depth":13,"bounds":{"left":0.17819148,"top":0.8762969,"width":0.042386968,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:3353","depth":13,"bounds":{"left":0.25748006,"top":0.86352754,"width":0.053025264,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"bounds":{"left":0.33743352,"top":0.86352754,"width":0.026928192,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"bounds":{"left":0.38131648,"top":0.86352754,"width":0.013131649,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"bounds":{"left":0.41489363,"top":0.86352754,"width":0.014793883,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"bounds":{"left":0.44913563,"top":0.86352754,"width":0.004986702,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"bounds":{"left":0.44913563,"top":0.86472464,"width":0.004986702,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"dawarich.lakylak.xyz","depth":12,"bounds":{"left":0.18085106,"top":0.91460496,"width":0.034574468,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 25th August 2025","depth":13,"bounds":{"left":0.17819148,"top":0.93615323,"width":0.04737367,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:3000","depth":13,"bounds":{"left":0.25748006,"top":0.92298484,"width":0.053025264,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"bounds":{"left":0.33743352,"top":0.92298484,"width":0.026928192,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"bounds":{"left":0.38131648,"top":0.92298484,"width":0.013131649,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"bounds":{"left":0.41489363,"top":0.92298484,"width":0.014793883,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"bounds":{"left":0.44913563,"top":0.92298484,"width":0.004986702,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"bounds":{"left":0.44913563,"top":0.92418194,"width":0.004986702,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"db.screenpipe.lakylak.xyz","depth":12,"bounds":{"left":0.18085106,"top":0.97406226,"width":0.04288564,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 27th April 2026","depth":13,"bounds":{"left":0.17819148,"top":0.99561054,"width":0.04338431,"height":0.004389465},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:8767","depth":13,"bounds":{"left":0.25748006,"top":0.9828412,"width":0.053025264,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"bounds":{"left":0.33743352,"top":0.9828412,"width":0.026928192,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"bounds":{"left":0.38131648,"top":0.9828412,"width":0.013131649,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"bounds":{"left":0.41489363,"top":0.9828412,"width":0.014793883,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"bounds":{"left":0.44913563,"top":0.9828412,"width":0.004986702,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"bounds":{"left":0.44913563,"top":0.9840383,"width":0.004986702,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"dsk-uploader.lakylak.xyz","depth":12,"bounds":{"left":0.18085106,"top":1.0,"width":0.04089096,"height":-0.033519506},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 15th August 2025","depth":13,"bounds":{"left":0.17819148,"top":1.0,"width":0.04737367,"height":-0.055067778},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:8502","depth":13,"bounds":{"left":0.25748006,"top":1.0,"width":0.053025264,"height":-0.042298436},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"bounds":{"left":0.33743352,"top":1.0,"width":0.026928192,"height":-0.042298436},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"bounds":{"left":0.38131648,"top":1.0,"width":0.013131649,"height":-0.042298436},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"bounds":{"left":0.41489363,"top":1.0,"width":0.014793883,"height":-0.042298436},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"bounds":{"left":0.44913563,"top":1.0,"width":0.004986702,"height":-0.042298436},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"bounds":{"left":0.44913563,"top":1.0,"width":0.004986702,"height":-0.043495655},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"gitea.lakylak.xyz","depth":12,"bounds":{"left":0.18085106,"top":1.0,"width":0.027426861,"height":-0.09337592},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 18th July 2025","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:3052","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"hydra.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 29th March 2026","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:4444","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"images.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 17th June 2025","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:3474","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"immich.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 15th June 2025","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:8212","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"jellyfin.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 15th June 2025","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:8096","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 15th June 2025","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:9999","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"linkwarden.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 13th December 2025","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:7461","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"location-tracker.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 30th August 2025","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:8050","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"log.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 23rd September 2025","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:18084","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"login.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 29th March 2026","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:4446","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"mcp.location.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 15th March 2026","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:8052","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"n8n.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 17th July 2025","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:5678","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"nas.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 28th July 2025","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:9999","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"notes.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 31st October 2025","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:8085","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"obsidian.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 17th June 2025","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:3421","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"outfit.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 25th March 2026","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:8667","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"owntracks.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 12th August 2025","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:8083","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"paperless.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 25th October 2025","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:8777","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"payments.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 14th February 2026","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:3010","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"pdf.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 19th June 2025","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:7890","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"portainer.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 15th June 2025","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:9000","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"sqlite.screenpipe.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 27th April 2026","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:8768","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"todo.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 16th March 2026","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://reminder-app:8000","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"tree.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 19th December 2025","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:8200","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"trilium.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 24th December 2025","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:4292","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"tube.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 3rd December 2025","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:8770","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ytber.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 11th March 2026","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:8100","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
7664839791160066303
|
-7811744194223492801
|
click
|
accessibility
|
NULL
|
Pull requests · screenpipe/screenpipe · GitHub
Pul Pull requests · screenpipe/screenpipe · GitHub
Pull requests · screenpipe/screenpipe · GitHub
Nginx Proxy Manager
Nginx Proxy Manager
Close tab
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
AFFiNE - All In One KnowledgeOS
AFFiNE - All In One KnowledgeOS
All docs · AFFiNE
All docs · AFFiNE
Payments Logger
Payments Logger
[NirDiamant/GenAI_Agents] Add SwarmScore — Portable Trust Rating for AI Agents (Issue #115) - [EMAIL] - Gmail
[NirDiamant/GenAI_Agents] Add SwarmScore — Portable Trust Rating for AI Agents (Issue #115) - [EMAIL] - Gmail
New Tab
New Tab
Location Logger
Location Logger
Finance Hub
Finance Hub
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Nginx Proxy Manager
Nginx Proxy Manager
Admin Administrator
Admin
Administrator
Dashboard
Dashboard
Hosts
Hosts
Access Lists
Access Lists
SSL Certificates
SSL Certificates
Users
Users
Audit Log
Audit Log
Settings
Settings
Proxy Hosts
Proxy Hosts
Search Host…
Add Proxy Host
Add Proxy Host
SOURCE
DESTINATION
SSL
ACCESS
STATUS
ai.chat.lakylak.xyz
Created: 10th March 2026
http://[IP_ADDRESS]:11000
Let's Encrypt
Public
Online
app.lakylak.xyz
Created: 19th July 2025
http://[IP_ADDRESS]:18083
Let's Encrypt
Public
Online
app.payments.lakylak.xyz
Created: 14th February 2026
http://[IP_ADDRESS]:5174
Let's Encrypt
Public
Online
app.screenpipe.lakylak.xyz
Created: 27th April 2026
http://[IP_ADDRESS]:8766
Let's Encrypt
Public
Online
audiobook.lakylak.xyz
Created: 15th June 2025
http://192.168..242:13378
Let's Encrypt
Public
Online
auth.lakylak.xyz
Created: 30th March 2026
http://[IP_ADDRESS]:9100
Let's Encrypt
Public
Online
backup.lakylak.xyz
Created: 10th July 2025
http://[IP_ADDRESS]:9999
Let's Encrypt
Public
Online
beszel.lakylak.xyz
Created: 6th December 2025
http://[IP_ADDRESS]:8095
Let's Encrypt
Public
Online
bitwarden.lakylak.xyz
Created: 16th June 2025
http://[IP_ADDRESS]:9890
Let's Encrypt
Public
Online
book.lakylak.xyz
Created: 31st October 2025
http://[IP_ADDRESS]:6060
Let's Encrypt
Public
Online
crm.lakylak.xyz
Created: 25th July 2025
http://[IP_ADDRESS]:3353
Let's Encrypt
Public
Online
dawarich.lakylak.xyz
Created: 25th August 2025
http://[IP_ADDRESS]:3000
Let's Encrypt
Public
Online
db.screenpipe.lakylak.xyz
Created: 27th April 2026
http://[IP_ADDRESS]:8767
Let's Encrypt
Public
Online
dsk-uploader.lakylak.xyz
Created: 15th August 2025
http://[IP_ADDRESS]:8502
Let's Encrypt
Public
Online
gitea.lakylak.xyz
Created: 18th July 2025
http://[IP_ADDRESS]:3052
Let's Encrypt
Public
Online
hydra.lakylak.xyz
Created: 29th March 2026
http://[IP_ADDRESS]:4444
Let's Encrypt
Public
Online
images.lakylak.xyz
Created: 17th June 2025
http://[IP_ADDRESS]:3474
Let's Encrypt
Public
Online
immich.lakylak.xyz
Created: 15th June 2025
http://[IP_ADDRESS]:8212
Let's Encrypt
Public
Online
jellyfin.lakylak.xyz
Created: 15th June 2025
http://[IP_ADDRESS]:8096
Let's Encrypt
Public
Online
lakylak.xyz
Created: 15th June 2025
http://[IP_ADDRESS]:9999
Let's Encrypt
Public
Online
linkwarden.lakylak.xyz
Created: 13th December 2025
http://[IP_ADDRESS]:7461
Let's Encrypt
Public
Online
location-tracker.lakylak.xyz
Created: 30th August 2025
http://[IP_ADDRESS]:8050
Let's Encrypt
Public
Online
log.lakylak.xyz
Created: 23rd September 2025
http://[IP_ADDRESS]:18084
Let's Encrypt
Public
Online
login.lakylak.xyz
Created: 29th March 2026
http://[IP_ADDRESS]:4446
Let's Encrypt
Public
Online
mcp.location.lakylak.xyz
Created: 15th March 2026
http://[IP_ADDRESS]:8052
Let's Encrypt
Public
Online
n8n.lakylak.xyz
Created: 17th July 2025
http://[IP_ADDRESS]:5678
Let's Encrypt
Public
Online
nas.lakylak.xyz
Created: 28th July 2025
http://[IP_ADDRESS]:9999
Let's Encrypt
Public
Online
notes.lakylak.xyz
Created: 31st October 2025
http://[IP_ADDRESS]:8085
Let's Encrypt
Public
Online
obsidian.lakylak.xyz
Created: 17th June 2025
http://[IP_ADDRESS]:3421
Let's Encrypt
Public
Online
outfit.lakylak.xyz
Created: 25th March 2026
http://[IP_ADDRESS]:8667
Let's Encrypt
Public
Online
owntracks.lakylak.xyz
Created: 12th August 2025
http://[IP_ADDRESS]:8083
Let's Encrypt
Public
Online
paperless.lakylak.xyz
Created: 25th October 2025
http://[IP_ADDRESS]:8777
Let's Encrypt
Public
Online
payments.lakylak.xyz
Created: 14th February 2026
http://[IP_ADDRESS]:3010
Let's Encrypt
Public
Online
pdf.lakylak.xyz
Created: 19th June 2025
http://[IP_ADDRESS]:7890
Let's Encrypt
Public
Online
portainer.lakylak.xyz
Created: 15th June 2025
http://[IP_ADDRESS]:9000
Let's Encrypt
Public
Online
sqlite.screenpipe.lakylak.xyz
Created: 27th April 2026
http://[IP_ADDRESS]:8768
Let's Encrypt
Public
Online
todo.lakylak.xyz
Created: 16th March 2026
http://reminder-app:8000
Let's Encrypt
Public
Online
tree.lakylak.xyz
Created: 19th December 2025
http://[IP_ADDRESS]:8200
Let's Encrypt
Public
Online
trilium.lakylak.xyz
Created: 24th December 2025
http://[IP_ADDRESS]:4292
Let's Encrypt
Public
Online
tube.lakylak.xyz
Created: 3rd December 2025
http://[IP_ADDRESS]:8770
Let's Encrypt
Public
Online
ytber.lakylak.xyz
Created: 11th March 2026
http://[IP_ADDRESS]:8100
Let's Encrypt
Public
Online...
|
11427
|
NULL
|
NULL
|
NULL
|
|
11443
|
515
|
43
|
2026-05-08T19:17:14.603912+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778267834603_m1.jpg...
|
Safari
|
hPanel - Hostinger
|
True
|
https://hpanel.hostinger.com
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Back
Bookmarks
Search
Favourites
Favourites
Favour Back
Bookmarks
Search
Favourites
Favourites
Favourites
iCloud
iCloud
iCloud
Google
Google
Google
APP DEV
APP DEV
APP DEV
ChatGPT
ChatGPT
ChatGPT
Domov • HBO Max
Domov • HBO Max
Domov • HBO Max
Tab Group Favourites
Tab Group Favourites
Tab Group Favourites
NAS
NAS
NAS
Home
Home
Home
Portainer
Portainer
Portainer
Nginx Proxy Manager
Nginx Proxy Manager
Nginx Proxy Manager
App
App
App
Bitwarden Web vault
Bitwarden Web vault
Bitwarden Web vault
PDF Stirling
PDF Stirling
PDF Stirling
n8n
n8n
n8n
Jellyfin
Jellyfin
Jellyfin
Immich
Immich
Immich
CRM
CRM
CRM
Gitea
Gitea
Gitea
Images
Images
Images
DSK Uploader
DSK Uploader
DSK Uploader
owntracks recorder
owntracks recorder
owntracks recorder
Map | Dawarich
Map | Dawarich
Map | Dawarich
Audiobookshelf
Audiobookshelf
Audiobookshelf
TubeArchivist
TubeArchivist
TubeArchivist
Beszel
Beszel
Beszel
booklore
booklore
booklore
Location Logger API - Swagger UI
Location Logger API - Swagger UI
Location Logger API - Swagger UI
Open WebUI
Open WebUI
Open WebUI
Paperless-ngx
Paperless-ngx
Paperless-ngx
Hostinger
Hostinger
Hostinger
Trilium Notes
Trilium Notes
Trilium Notes
Location Logger
Location Logger
Location Logger
Outfit Manager
Outfit Manager
Outfit Manager
Reminders
Reminders
Reminders
g
g
g
PROTON
PROTON
PROTON
TubeArchivist
UGREEN NAS
Audiobookshelf
PortNote
MAZANOKE | Online Image Optimizer That Runs Privately in Your Browser
Next Beats | Your Ultimate Music Experience
Obsidian
Omni Tools
hPanel - Hostinger
close tab...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Back","depth":3,"on_screen":true,"automation_id":"LibrarySidebarNavigationViewController.returnButton","role_description":"button","is_enabled":true,"is_focused":false},{"role":"AXStaticText","text":"Bookmarks","depth":3,"on_screen":true,"automation_id":"LibrarySidebarNavigationViewController._viewLabel","role_description":"text"},{"role":"AXButton","text":"Search","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false},{"role":"AXCell","text":"Favourites","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXTextField","text":"Favourites","depth":7,"on_screen":true,"automation_id":"BookmarksSidebarTableFolderCellView","role_description":"text field","is_focused":false},{"role":"AXTextField","text":"Favourites","depth":8,"on_screen":true,"automation_id":"_NS:7","value":"Favourites","role_description":"text field","is_enabled":true,"is_focused":false},{"role":"AXCell","text":"iCloud","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXTextField","text":"iCloud","depth":7,"on_screen":true,"automation_id":"BookmarksSidebarTableCellView","role_description":"text field","is_focused":false},{"role":"AXTextField","text":"iCloud","depth":8,"on_screen":true,"automation_id":"_NS:7","value":"iCloud","role_description":"text field","is_enabled":true,"is_focused":false},{"role":"AXCell","text":"Google","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXTextField","text":"Google","depth":7,"on_screen":true,"automation_id":"BookmarksSidebarTableCellView","role_description":"text field","is_focused":false},{"role":"AXTextField","text":"Google","depth":8,"on_screen":true,"automation_id":"_NS:7","value":"Google","role_description":"text field","is_enabled":true,"is_focused":false},{"role":"AXCell","text":"APP DEV","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXTextField","text":"APP DEV","depth":7,"on_screen":true,"automation_id":"BookmarksSidebarTableCellView","role_description":"text field","is_focused":false},{"role":"AXTextField","text":"APP DEV","depth":8,"on_screen":true,"automation_id":"_NS:7","value":"APP DEV","role_description":"text field","is_enabled":true,"is_focused":false},{"role":"AXCell","text":"ChatGPT","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXTextField","text":"ChatGPT","depth":7,"on_screen":true,"automation_id":"BookmarksSidebarTableCellView","role_description":"text field","is_focused":false},{"role":"AXTextField","text":"ChatGPT","depth":8,"on_screen":true,"automation_id":"_NS:7","value":"ChatGPT","role_description":"text field","is_enabled":true,"is_focused":false},{"role":"AXCell","text":"Domov • HBO Max","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXTextField","text":"Domov • HBO Max","depth":7,"on_screen":true,"automation_id":"BookmarksSidebarTableCellView","role_description":"text field","is_focused":false},{"role":"AXTextField","text":"Domov • HBO Max","depth":8,"on_screen":true,"automation_id":"_NS:7","value":"Domov • HBO Max","role_description":"text field","is_enabled":true,"is_focused":false},{"role":"AXCell","text":"Tab Group Favourites","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXTextField","text":"Tab Group Favourites","depth":7,"on_screen":true,"automation_id":"BookmarksSidebarTableFolderCellView","role_description":"text field","is_focused":false},{"role":"AXTextField","text":"Tab Group Favourites","depth":8,"on_screen":true,"automation_id":"_NS:7","value":"Tab Group Favourites","role_description":"text field","is_enabled":true,"is_focused":false},{"role":"AXCell","text":"NAS","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXTextField","text":"NAS","depth":7,"on_screen":true,"automation_id":"BookmarksSidebarTableFolderCellView","role_description":"text field","is_focused":false},{"role":"AXTextField","text":"NAS","depth":8,"on_screen":true,"automation_id":"_NS:7","value":"NAS","role_description":"text field","is_enabled":true,"is_focused":false},{"role":"AXCell","text":"Home","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXTextField","text":"Home","depth":7,"on_screen":true,"automation_id":"BookmarksSidebarTableCellView","role_description":"text field","is_focused":false},{"role":"AXTextField","text":"Home","depth":8,"on_screen":true,"automation_id":"_NS:7","value":"Home","role_description":"text field","is_enabled":true,"is_focused":false},{"role":"AXCell","text":"Portainer","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXTextField","text":"Portainer","depth":7,"on_screen":true,"automation_id":"BookmarksSidebarTableCellView","role_description":"text field","is_focused":false},{"role":"AXTextField","text":"Portainer","depth":8,"on_screen":true,"automation_id":"_NS:7","value":"Portainer","role_description":"text field","is_enabled":true,"is_focused":false},{"role":"AXCell","text":"Nginx Proxy Manager","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXTextField","text":"Nginx Proxy Manager","depth":7,"on_screen":true,"automation_id":"BookmarksSidebarTableCellView","role_description":"text field","is_focused":false},{"role":"AXTextField","text":"Nginx Proxy Manager","depth":8,"on_screen":true,"automation_id":"_NS:7","value":"Nginx Proxy Manager","role_description":"text field","is_enabled":true,"is_focused":false},{"role":"AXCell","text":"App","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXTextField","text":"App","depth":7,"on_screen":true,"automation_id":"BookmarksSidebarTableCellView","role_description":"text field","is_focused":false},{"role":"AXTextField","text":"App","depth":8,"on_screen":true,"automation_id":"_NS:7","value":"App","role_description":"text field","is_enabled":true,"is_focused":false},{"role":"AXCell","text":"Bitwarden Web vault","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXTextField","text":"Bitwarden Web vault","depth":7,"on_screen":true,"automation_id":"BookmarksSidebarTableCellView","role_description":"text field","is_focused":false},{"role":"AXTextField","text":"Bitwarden Web vault","depth":8,"on_screen":true,"automation_id":"_NS:7","value":"Bitwarden Web vault","role_description":"text field","is_enabled":true,"is_focused":false},{"role":"AXCell","text":"PDF Stirling","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXTextField","text":"PDF Stirling","depth":7,"on_screen":true,"automation_id":"BookmarksSidebarTableCellView","role_description":"text field","is_focused":false},{"role":"AXTextField","text":"PDF Stirling","depth":8,"on_screen":true,"automation_id":"_NS:7","value":"PDF Stirling","role_description":"text field","is_enabled":true,"is_focused":false},{"role":"AXCell","text":"n8n","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXTextField","text":"n8n","depth":7,"on_screen":true,"automation_id":"BookmarksSidebarTableCellView","role_description":"text field","is_focused":false},{"role":"AXTextField","text":"n8n","depth":8,"on_screen":true,"automation_id":"_NS:7","value":"n8n","role_description":"text field","is_enabled":true,"is_focused":false},{"role":"AXCell","text":"Jellyfin","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXTextField","text":"Jellyfin","depth":7,"on_screen":true,"automation_id":"BookmarksSidebarTableCellView","role_description":"text field","is_focused":false},{"role":"AXTextField","text":"Jellyfin","depth":8,"on_screen":true,"automation_id":"_NS:7","value":"Jellyfin","role_description":"text field","is_enabled":true,"is_focused":false},{"role":"AXCell","text":"Immich","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXTextField","text":"Immich","depth":7,"on_screen":true,"automation_id":"BookmarksSidebarTableCellView","role_description":"text field","is_focused":false},{"role":"AXTextField","text":"Immich","depth":8,"on_screen":true,"automation_id":"_NS:7","value":"Immich","role_description":"text field","is_enabled":true,"is_focused":false},{"role":"AXCell","text":"CRM","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXTextField","text":"CRM","depth":7,"on_screen":true,"automation_id":"BookmarksSidebarTableCellView","role_description":"text field","is_focused":false},{"role":"AXTextField","text":"CRM","depth":8,"on_screen":true,"automation_id":"_NS:7","value":"CRM","role_description":"text field","is_enabled":true,"is_focused":false},{"role":"AXCell","text":"Gitea","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXTextField","text":"Gitea","depth":7,"on_screen":true,"automation_id":"BookmarksSidebarTableCellView","role_description":"text field","is_focused":false},{"role":"AXTextField","text":"Gitea","depth":8,"on_screen":true,"automation_id":"_NS:7","value":"Gitea","role_description":"text field","is_enabled":true,"is_focused":false},{"role":"AXCell","text":"Images","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXTextField","text":"Images","depth":7,"on_screen":true,"automation_id":"BookmarksSidebarTableCellView","role_description":"text field","is_focused":false},{"role":"AXTextField","text":"Images","depth":8,"on_screen":true,"automation_id":"_NS:7","value":"Images","role_description":"text field","is_enabled":true,"is_focused":false},{"role":"AXCell","text":"DSK Uploader","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXTextField","text":"DSK Uploader","depth":7,"on_screen":true,"automation_id":"BookmarksSidebarTableCellView","role_description":"text field","is_focused":false},{"role":"AXTextField","text":"DSK Uploader","depth":8,"on_screen":true,"automation_id":"_NS:7","value":"DSK Uploader","role_description":"text field","is_enabled":true,"is_focused":false},{"role":"AXCell","text":"owntracks recorder","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXTextField","text":"owntracks recorder","depth":7,"on_screen":true,"automation_id":"BookmarksSidebarTableCellView","role_description":"text field","is_focused":false},{"role":"AXTextField","text":"owntracks recorder","depth":8,"on_screen":true,"automation_id":"_NS:7","value":"owntracks recorder","role_description":"text field","is_enabled":true,"is_focused":false},{"role":"AXCell","text":"Map | Dawarich","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXTextField","text":"Map | Dawarich","depth":7,"on_screen":true,"automation_id":"BookmarksSidebarTableCellView","role_description":"text field","is_focused":false},{"role":"AXTextField","text":"Map | Dawarich","depth":8,"on_screen":true,"automation_id":"_NS:7","value":"Map | Dawarich","role_description":"text field","is_enabled":true,"is_focused":false},{"role":"AXCell","text":"Audiobookshelf","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXTextField","text":"Audiobookshelf","depth":7,"on_screen":true,"automation_id":"BookmarksSidebarTableCellView","role_description":"text field","is_focused":false},{"role":"AXTextField","text":"Audiobookshelf","depth":8,"on_screen":true,"automation_id":"_NS:7","value":"Audiobookshelf","role_description":"text field","is_enabled":true,"is_focused":false},{"role":"AXCell","text":"TubeArchivist","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXTextField","text":"TubeArchivist","depth":7,"on_screen":true,"automation_id":"BookmarksSidebarTableCellView","role_description":"text field","is_focused":false},{"role":"AXTextField","text":"TubeArchivist","depth":8,"on_screen":true,"automation_id":"_NS:7","value":"TubeArchivist","role_description":"text field","is_enabled":true,"is_focused":false},{"role":"AXCell","text":"Beszel","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXTextField","text":"Beszel","depth":7,"on_screen":true,"automation_id":"BookmarksSidebarTableCellView","role_description":"text field","is_focused":false},{"role":"AXTextField","text":"Beszel","depth":8,"on_screen":true,"automation_id":"_NS:7","value":"Beszel","role_description":"text field","is_enabled":true,"is_focused":false},{"role":"AXCell","text":"booklore","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXTextField","text":"booklore","depth":7,"on_screen":true,"automation_id":"BookmarksSidebarTableCellView","role_description":"text field","is_focused":false},{"role":"AXTextField","text":"booklore","depth":8,"on_screen":true,"automation_id":"_NS:7","value":"booklore","role_description":"text field","is_enabled":true,"is_focused":false},{"role":"AXCell","text":"Location Logger API - Swagger UI","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXTextField","text":"Location Logger API - Swagger UI","depth":7,"on_screen":true,"automation_id":"BookmarksSidebarTableCellView","role_description":"text field","is_focused":false},{"role":"AXTextField","text":"Location Logger API - Swagger UI","depth":8,"on_screen":true,"automation_id":"_NS:7","value":"Location Logger API - Swagger UI","role_description":"text field","is_enabled":true,"is_focused":false},{"role":"AXCell","text":"Open WebUI","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXTextField","text":"Open WebUI","depth":7,"on_screen":true,"automation_id":"BookmarksSidebarTableCellView","role_description":"text field","is_focused":false},{"role":"AXTextField","text":"Open WebUI","depth":8,"on_screen":true,"automation_id":"_NS:7","value":"Open WebUI","role_description":"text field","is_enabled":true,"is_focused":false},{"role":"AXCell","text":"Paperless-ngx","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXTextField","text":"Paperless-ngx","depth":7,"on_screen":true,"automation_id":"BookmarksSidebarTableCellView","role_description":"text field","is_focused":false},{"role":"AXTextField","text":"Paperless-ngx","depth":8,"on_screen":true,"automation_id":"_NS:7","value":"Paperless-ngx","role_description":"text field","is_enabled":true,"is_focused":false},{"role":"AXCell","text":"Hostinger","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXTextField","text":"Hostinger","depth":7,"on_screen":true,"automation_id":"BookmarksSidebarTableCellView","role_description":"text field","is_focused":false},{"role":"AXTextField","text":"Hostinger","depth":8,"on_screen":true,"automation_id":"_NS:7","value":"Hostinger","role_description":"text field","is_enabled":true,"is_focused":false},{"role":"AXCell","text":"Trilium Notes","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXTextField","text":"Trilium Notes","depth":7,"on_screen":true,"automation_id":"BookmarksSidebarTableCellView","role_description":"text field","is_focused":false},{"role":"AXTextField","text":"Trilium Notes","depth":8,"on_screen":true,"automation_id":"_NS:7","value":"Trilium Notes","role_description":"text field","is_enabled":true,"is_focused":false},{"role":"AXCell","text":"Location Logger","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXTextField","text":"Location Logger","depth":7,"on_screen":true,"automation_id":"BookmarksSidebarTableCellView","role_description":"text field","is_focused":false},{"role":"AXTextField","text":"Location Logger","depth":8,"on_screen":true,"automation_id":"_NS:7","value":"Location Logger","role_description":"text field","is_enabled":true,"is_focused":false},{"role":"AXCell","text":"Outfit Manager","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXTextField","text":"Outfit Manager","depth":7,"on_screen":true,"automation_id":"BookmarksSidebarTableCellView","role_description":"text field","is_focused":false},{"role":"AXTextField","text":"Outfit Manager","depth":8,"on_screen":true,"automation_id":"_NS:7","value":"Outfit Manager","role_description":"text field","is_enabled":true,"is_focused":false},{"role":"AXCell","text":"Reminders","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXTextField","text":"Reminders","depth":7,"on_screen":true,"automation_id":"BookmarksSidebarTableCellView","role_description":"text field","is_focused":false},{"role":"AXTextField","text":"Reminders","depth":8,"on_screen":true,"automation_id":"_NS:7","value":"Reminders","role_description":"text field","is_enabled":true,"is_focused":false},{"role":"AXCell","text":"g","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXTextField","text":"g","depth":7,"on_screen":true,"automation_id":"BookmarksSidebarTableFolderCellView","role_description":"text field","is_focused":false},{"role":"AXTextField","text":"g","depth":8,"on_screen":true,"automation_id":"_NS:7","value":"g","role_description":"text field","is_enabled":true,"is_focused":false},{"role":"AXCell","text":"PROTON","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXTextField","text":"PROTON","depth":7,"on_screen":true,"automation_id":"BookmarksSidebarTableFolderCellView","role_description":"text field","is_focused":false},{"role":"AXTextField","text":"PROTON","depth":8,"on_screen":true,"automation_id":"_NS:7","value":"PROTON","role_description":"text field","is_enabled":true,"is_focused":false},{"role":"AXRadioButton","text":"TubeArchivist","depth":2,"on_screen":true,"automation_id":"TabBarTab?isNarrow=true&isPinned=true","role_description":"pinned tab","subrole":"AXTabButton","is_focused":false},{"role":"AXRadioButton","text":"UGREEN NAS","depth":2,"on_screen":true,"automation_id":"TabBarTab?isNarrow=true&isPinned=true","role_description":"pinned tab","subrole":"AXTabButton","is_focused":false},{"role":"AXRadioButton","text":"Audiobookshelf","depth":2,"on_screen":true,"automation_id":"TabBarTab?isNarrow=true&isPinned=true","role_description":"pinned tab","subrole":"AXTabButton","is_focused":false},{"role":"AXRadioButton","text":"PortNote","depth":2,"on_screen":true,"automation_id":"TabBarTab?isNarrow=true&isPinned=true","role_description":"pinned tab","subrole":"AXTabButton","is_focused":false},{"role":"AXRadioButton","text":"MAZANOKE | Online Image Optimizer That Runs Privately in Your Browser","depth":2,"on_screen":true,"automation_id":"TabBarTab?isNarrow=true&isPinned=true","role_description":"pinned tab","subrole":"AXTabButton","is_focused":false},{"role":"AXRadioButton","text":"Next Beats | Your Ultimate Music Experience","depth":2,"on_screen":true,"automation_id":"TabBarTab?isNarrow=true&isPinned=true","role_description":"pinned tab","subrole":"AXTabButton","is_focused":false},{"role":"AXRadioButton","text":"Obsidian","depth":2,"on_screen":true,"automation_id":"TabBarTab?isNarrow=true&isPinned=true","role_description":"pinned tab","subrole":"AXTabButton","is_focused":false},{"role":"AXRadioButton","text":"Omni Tools","depth":2,"on_screen":true,"automation_id":"TabBarTab?isNarrow=true&isPinned=true","role_description":"pinned tab","subrole":"AXTabButton","is_focused":false},{"role":"AXRadioButton","text":"hPanel - Hostinger","depth":2,"on_screen":true,"automation_id":"TabBarTab?isNarrow=false&isPinned=false","role_description":"tab","subrole":"AXTabButton","is_focused":false},{"role":"AXButton","text":"close tab","depth":3,"on_screen":true,"automation_id":"CloseTabBarItemButton","role_description":"button","is_enabled":true,"is_focused":false}]...
|
-4220002380381841310
|
2457027307664779685
|
click
|
accessibility
|
NULL
|
Back
Bookmarks
Search
Favourites
Favourites
Favour Back
Bookmarks
Search
Favourites
Favourites
Favourites
iCloud
iCloud
iCloud
Google
Google
Google
APP DEV
APP DEV
APP DEV
ChatGPT
ChatGPT
ChatGPT
Domov • HBO Max
Domov • HBO Max
Domov • HBO Max
Tab Group Favourites
Tab Group Favourites
Tab Group Favourites
NAS
NAS
NAS
Home
Home
Home
Portainer
Portainer
Portainer
Nginx Proxy Manager
Nginx Proxy Manager
Nginx Proxy Manager
App
App
App
Bitwarden Web vault
Bitwarden Web vault
Bitwarden Web vault
PDF Stirling
PDF Stirling
PDF Stirling
n8n
n8n
n8n
Jellyfin
Jellyfin
Jellyfin
Immich
Immich
Immich
CRM
CRM
CRM
Gitea
Gitea
Gitea
Images
Images
Images
DSK Uploader
DSK Uploader
DSK Uploader
owntracks recorder
owntracks recorder
owntracks recorder
Map | Dawarich
Map | Dawarich
Map | Dawarich
Audiobookshelf
Audiobookshelf
Audiobookshelf
TubeArchivist
TubeArchivist
TubeArchivist
Beszel
Beszel
Beszel
booklore
booklore
booklore
Location Logger API - Swagger UI
Location Logger API - Swagger UI
Location Logger API - Swagger UI
Open WebUI
Open WebUI
Open WebUI
Paperless-ngx
Paperless-ngx
Paperless-ngx
Hostinger
Hostinger
Hostinger
Trilium Notes
Trilium Notes
Trilium Notes
Location Logger
Location Logger
Location Logger
Outfit Manager
Outfit Manager
Outfit Manager
Reminders
Reminders
Reminders
g
g
g
PROTON
PROTON
PROTON
TubeArchivist
UGREEN NAS
Audiobookshelf
PortNote
MAZANOKE | Online Image Optimizer That Runs Privately in Your Browser
Next Beats | Your Ultimate Music Experience
Obsidian
Omni Tools
hPanel - Hostinger
close tab...
|
11439
|
NULL
|
NULL
|
NULL
|
|
11633
|
520
|
43
|
2026-05-09T06:42:55.653635+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-09/1778 /Users/lukas/.screenpipe/data/data/2026-05-09/1778308975653_m2.jpg...
|
Code
|
Design new payment-logge… — finance [SSH: nas]
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Explorer (⇧⌘E)
Search (⇧⌘F)
Source Control (⌃⇧ Explorer (⇧⌘E)
Search (⇧⌘F)
Source Control (⌃⇧G)
Run and Debug (⇧⌘D)
Remote Explorer
Extensions (⇧⌘X) - 2 require update
2
Claude Code
Containers
EXPLORER
EXPLORER
Explorer Section: finance [SSH: nas]
Explorer Section: finance [SSH: nas]
FINANCE [SSH: NAS]
auth
dsk-uploader
finance-hub
backend
frontend
.env
.env.example
.gitignore
docker-compose.yml
payments-logger
Outline Section
OUTLINE
OUTLINE
Timeline Section
TIMELINE
TIMELINE
docker-compose.yml, Editor Group 1
.env, Editor Group 1
version: '3.8'
services:
db:
image: postgres:16-alpine
restart: unless-stopped
environment:
POSTGRES_USER: finance
POSTGRES_PASSWORD: [PASSWORD]
POSTGRES_DB: finance_hub
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U finance -d finance_hub"]
interval: 5s
timeout: 5s
retries: 5
backend:
build: ./backend
restart: unless-stopped
environment:
DATABASE_URL: [CONNECTION_STRING]
PORT: "3001"
NOTIFIER_URL: ${NOTIFIER_URL}
NOTIFIER_CHANNEL: ${NOTIFIER_CHANNEL:-viber}
NOTIFY_DEFAULT_PHONE: ${NOTIFY_DEFAULT_PHONE}
TZ: ${TZ:-Europe/Sofia}
ports:
- "${BACKEND_PORT:-3001}:3001"
depends_on:
db:
condition: service_healthy
frontend:
build: ./frontend
restart: unless-stopped
ports:
- "${FRONTEND_PORT:-5175}:5173"
depends_on:
- backend
volumes:
pgdata:
version: '3.8'
services:
db:
image: postgres:16-alpine
restart: unless-stopped
environment:
POSTGRES_USER: finance
POSTGRES_PASSWORD: [PASSWORD]
POSTGRES_DB: finance_hub
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U finance -d finance_hub"]
interval: 5s
timeout: 5s
retries: 5
backend:
build: ./backend
restart: unless-stopped
environment:
DATABASE_URL: [CONNECTION_STRING]
PORT: "3001"
NOTIFIER_URL: ${NOTIFIER_URL}
NOTIFIER_CHANNEL: ${NOTIFIER_CHANNEL:-viber}
NOTIFY_DEFAULT_PHONE: ${NOTIFY_DEFAULT_PHONE}
TZ: ${TZ:-Europe/Sofia}
ports:
- "${BACKEND_PORT:-3001}:3001"
depends_on:
db:
condition: service_healthy
frontend:
build: ./frontend
restart: unless-stopped
ports:
- "${FRONTEND_PORT:-5175}:5173"
depends_on:
- backend
volumes:
pgdata:
Design new payment-logge…, Editor Group 2
remote SSH: nas
SSH: nas
No Problems
0
0
No Ports Forwarded
0
Notifications
Sign In
Sign In
Info: Setting up SSH Host nas: Setting up SSH tunnel
Design new payment-logger and dsk-uploader hybrid app
Session history
New session
Message actions
payments.js
payments.js
ets create a new app that should be combination of payment-logger and dsk-uploader. It should have authorization via authentik (auth folder). All three folders (payment-logger, dsk-uploader and auth) are just refference these will be removed later. Auth project is separated it lives on its own. First reveiw them and see how these should be combined. It will be whole new app (also the folder name). Think very carefully of whatr these two apps do and how cold they be combined. THerer should be common db and uploader should store data the same way the /ingest does. It should be properly marked in UI if it is upload or ingest or both. FIrst think of tech stack and plan carefully.
Thinking
Thinking
I'll explore all three reference projects in parallel to understand their structure before planning.
Agent:
Explore payment-logger app structure and functionality
IN
Explore the /volume2/docker/finance/payments-logger directory thoroughly. I need to understand:
1. Tech stack (frontend framework, backend framework, database)
2. What the app does - its core purpose and features
3. Database schema - all tables, relationships
4. API routes - all endpoints, their purpose and request/response shapes
5. How data flows (ingest, storage, retrieval)
6. Any auth/middleware setup
7. Docker/deployment setup
8. Key files and their roles
Report with: directory structure, tech stack summary, database schema details, all API endpoints listed, UI features, and how data is ingested. Be thorough on the /ingest endpoint specifically.
Agent:
Explore dsk-uploader app structure and functionality
IN
Explore the /volume2/docker/finance/dsk-uploader directory thoroughly. I need to understand:
1. Tech stack (frontend framework, backend framework, database)
2. What the app does - its core purpose and features
3. Database schema - all tables, relationships
4. API routes - all endpoints, their purpose and request/response shapes
5. How file uploads work - what files, what format, how parsed
6. Any auth/middleware setup
7. Docker/deployment setup
8. Key files and their roles
Report with: directory structure, tech stack summary, database schema details, all API endpoints listed, UI features, how file upload parsing works, and what data is extracted from uploads. Be very thorough about the data model and what fields are stored.
Agent:
Explore auth folder and authentik integration
IN
Explore the /volume2/docker/finance/auth directory thoroughly. I need to understand:
1. What auth system is being used (Authentik)
2. How authentication/authorization is implemented - OAuth2, OIDC, session tokens, JWT?
3. Middleware - how is auth enforced on routes?
4. Any frontend auth flow - login redirect, token handling, protected routes
5. Environment variables related to auth
6. Docker/deployment setup for the auth service itself
7. Any example of how other apps integrate with this auth
Report with: directory structure, auth flow description, middleware code, environment variable names, and integration patterns. This is a reference for building auth into a new combined app.
Message actions
payments.js
payments.js
continue
Thinking
Thinking
Launching parallel exploration of all three reference projects.
Agent:
Explore payment-logger app structure
IN
Explore the /volume2/docker/finance/payments-logger directory thoroughly. I need to understand:
1. Full directory structure (tree)
2. Tech stack (frontend framework, backend framework, database, etc.)
3. What the app does - its core functionality
4. How data is ingested (look at /ingest route especially)
5. Database schema (what tables/collections exist)
6. API routes and their purposes
7. Frontend pages and components
8. Docker setup
9. Any auth/session handling
Please read key files: package.json files, main entry points, route files, database schema files, docker-compose.yml, and any frontend components. Be thorough - I need a complete picture to plan a new combined app.
Agent:
Explore dsk-uploader app structure
IN
Explore the /volume2/docker/finance/dsk-uploader directory thoroughly. I need to understand:
1. Full directory structure (tree)
2. Tech stack (frontend framework, backend framework, database, etc.)
3. What the app does - its core functionality
4. How file uploads work (what format, what processing happens)
5. Database schema (what tables/collections exist)
6. API routes and their purposes
7. Frontend pages and components
8. Docker setup
9. Any auth/session handling
Please read key files: package.json files, main entry points, route files, database schema files, docker-compose.yml, and any frontend components. Be thorough - I need a complete picture to plan a new combined app.
Agent:
Explore auth project structure
IN
Explore the /volume2/docker/finance/auth directory thoroughly. I need to understand:
1. Full directory structure (tree)
2. What authentication system is used (authentik integration details)
3. How OAuth/OIDC flow works
4. Any middleware or helper functions for protecting routes
5. Session management approach
6. How frontend handles auth state
7. Any example of how other apps integrate with this auth system
8. Docker setup and environment variables
Please read all files carefully - this auth system will be integrated into a new combined app. I need to understand exactly how to use it.
Thinking
Thinking
Now I have a complete picture of all three. Let me design the plan.
Agent:
Design combined app architecture
IN
Design a detailed implementation plan for a new combined web app that merges two existing applications. Here is full context:
---
## App 1: payments-logger (Node.js)
- **Purpose**: Ingest Bulgarian bank SMS → parse → store in PostgreSQL → review/tag/notify in React UI
- **Stack**: Node.js 20 + Express + Prisma 5 + PostgreSQL 16 + React 18 + Vite + Tailwind CSS
- **Auth**: Custom JWT (bcryptjs + jose), tokens in localStorage
- **Ingest**: POST /api/payments/ingest (public) — SMS text OR structured JSON (Apple Wallet)
- **Schema** (PostgreSQL via Prisma):
- `payments` table: id, raw_message, date, type (POS/ATM/INTERNET/ECOM/P2P/WALLET), card, recipient, amount, balance, status (UNPROCESSED/SENT/SKIPPED), notifyPhone, notifiedAt, created_at, updated_at
- `tags` table: id, name, color — M2M with payments via `_PaymentToTag`
- `users` table: id, username, hashed_password (this will be REMOVED)
- **UI**: Single-page React app — PaymentTable (sortable, filterable, taggable), FilterBar, status actions (send/skip), notification system
- **Parser** (backend/src/parser.js): Regex parser for Bulgarian DSK Bank SMS, extracts date/time (DD/MM/YYYY HH:MM), card mask, transaction type, recipient, amount, balance
## App 2: dsk-uploader (Python/Flask)
- **Purpose**: Upload DSK bank CSV exports → parse/normalize → upload to Notion database
- **Stack**: Python 3.11 + Flask + Pandas + Custom Notion SDK + Bootstrap 5
- **Auth**: None (open)
- **CSV format** (DSK Bank Bulgarian format, columns):
- `Дата` (date, DD.MM.YYYY)
- `Вид на трансакцията` (transaction type, Bulgarian)
- `Основание` (reason/description — contains card number regex: `^\d{6}x{6}\d{4}$`)
- `Дебит BGN` (debit amount, may be empty)
- `Кредит BGN` (credit amount, may be empty)
- `Наредител/Получател` (orderer/recipient name)
- `Номер сметка на наредителя / получателя` (account number)
- **Processing**: merge multiple CSVs, normalize dates, extract card numbers from reason via regex, auto-generate tags (keyword heuristics: ЗАПЛАТА→Salary, NETFLIX→Subscriptions, etc.), filter internal transfers
- **Output**: Notion database pages (this will be REPLACED with local PostgreSQL)
## App 3: auth (Authentik)
- **Mode**: Proxy mode via NPM (forward auth)
- **How it works**: NPM intercepts all requests, calls Authentik outpost's auth endpoint. On success, NPM injects headers into proxied request:
- `X-authentik-username`
- `X-authentik-email`
- `X-authentik-groups`
- **No code integration needed** in the app itself — just trust these headers from NPM
- **Logout**: Redirect user to `/outpost.goauthentik.io/sign_out`
---
## What the New Combined App Must Do
1. **Single PostgreSQL database** for all transactions
2. **SMS Ingest** (public endpoint) — same as payments-logger /ingest, source=INGEST
3. **CSV Upload** (authenticated) — parse DSK CSV files, store transactions with source=UPLOAD into the same DB schema
4. **Unified UI** — show all payments in one table regardless of source
5. **Source indicator** in UI — badge showing "INGEST", "UPLOAD", or "BOTH" (if duplicate detection added)
6. **Source filter** in FilterBar — filter by All/Ingest/Upload
7. **Authentik auth** — remove custom JWT entirely; trust X-authentik-* headers from NPM
8. **All existing payments-logger features**: tagging, send notification, skip, status tracking, filters, sorting, pagination
9. **Remove Notion dependency entirely** — all data stays in local PostgreSQL
---
## Technical Constraints
- Keep Node.js backend (not Python) — extend payments-logger's stack
- CSV parsing: use `csv-parse` npm package (handles encoding, streaming)
- File upload: use `multer` npm middleware
- Auth middleware: read X-authentik-username header, 401 if missing (but /api/payments/ingest stays public)
- Add `source` enum field (INGEST/UPLOAD) to payments schema
- Add `currency` field (EUR for SMS ingest, BGN for CSV uploads) — or just store as-is
- Remove `users` table from schema
---
## Please Design
1. Complete folder structure for the new app (suggest name: "finance-hub" or similar — note this is a placeholder, user will confirm)
2. Prisma schema with new fields (`source`, `currency`)
3. All backend API routes
4. CSV parser design in Node.js (port of the Python logic)
5. Authentik auth middleware
6. Frontend component structure (React) — what's reused from payments-logger, what's new
7. Docker Compose setup
8. Environment variables needed
9. Step-by-step implementation order
10. Verification checklist
Be specific about file paths and code structure. This will be used to write actual implementation code.
Thinking
Thinking
Good plan. Let me ask the one thing I need before writing the final plan.
AskUserQuestion
OUT
User has answered your questions: "What should the new combined app be called? This will be the folder name under /volume2/docker/finance/ and the app branding."="finance-hub". You can now continue with the user's answers in mind.
Thinking
Thinking
Writing the final plan now.
Thinking
Thinking
Write
ets-create-a-new-generic-sun.md
ets-create-a-new-generic-sun.md
326 lines
# finance-hub — Implementation Plan
## Context
Two separate finance apps exist as references and will be retired:
- **payments-logger** (Node.js/React): Ingests Bulgarian bank SMS notifications, stores payments in PostgreSQL, provides a review/tag/notify UI.
- **dsk-uploader** (Python/Flask): Uploads DSK bank CSV exports, parses them, sends to Notion.
The new app **finance-hub** (`/volume2/docker/finance/finance-hub/`) replaces both with a single unified system: all transactions (SMS-ingested and CSV-uploaded) land in one PostgreSQL database and one React UI. Authentication is delegated entirely to Authentik (proxy mode via NPM — no custom JWT).
---
## Tech Stack
| Layer | Choice | Rationale |
|-------|--------|-----------|
| Backend | Node.js 20 + Express + Prisma 5 | Extends payments-logger; no Python needed |
| CSV parsing | `csv-parse` + `iconv-lite` | Handles Bulgarian cp1251 encoding, RFC4180 quoted fields |
| File upload | `multer` (memory storage) | Bank CSVs are small (<500 KB), no disk cleanup needed |
| Database | PostgreSQL 16 | Same as payments-logger |
| Frontend | React 18 + Vite + Tailwind CSS + Lucide React | Same as payments-logger |
| Auth | Authentik proxy via NPM headers | No custom JWT; removes users table entirely |
| Container | Docker Compose | Same pattern as both reference apps |
**Removed vs payments-logger:** `bcryptjs`, `jose`, `users` table, login form, JWT storage.
**Removed vs dsk-uploader:** Python/Flask, Pandas, Notion SDK, all Notion references.
**Added:** `csv-parse`, `iconv-lite`, `multer`, `source` + `currency` fields, `UploadPanel` component.
---
## Folder Structure
```
/volume2/docker/finance/finance-hub/
├── docker-compose.yml
├── .env
├── .env.example
├── .gitignore
├── backend/
│ ├── Dockerfile
│ ├── package.json
│ ├── prisma/
│ │ ├── schema.prisma
│ │ └── migrations/
│ │ ├── migration_lock.toml
│ │ └── 20260508_init/
│ │ └── migration.sql
│ └── src/
│ ├── index.js ← entry point (Authentik middleware wired here)
│ ├── auth.js ← Authentik header middleware (replaces JWT auth)
│ ├── parser.js ← SMS parser (copy verbatim from payments-logger)
│ ├── csvParser.js ← NEW: DSK CSV parser (port of Python dskuploader.py)
│ └── routes/
│ ├── payments.js ← existing routes + source/currency additions
│ └── upload.js ← NEW: POST /api/upload/csv
└── frontend/
├── Dockerfile
├── package.json
├── vite.config.js
├── tailwind.config.js
├── postcss.config.js
├── index.html
└── src/
├── main.jsx ← remove AuthProvider wrapper
├── index.css
├── App.jsx ← remove auth state, add Upload tab toggle
└── components/
├── FilterBar.jsx ← add source filter select
├── PaymentTable.jsx ← add Source badge column + currency display
├── PaymentCard.jsx ← minor source badge addition
├── PaymentList.jsx ← unchanged
└── UploadPanel.jsx ← NEW: drag-and-drop CSV upload UI
```
---
## Database Schema (Prisma)
File: `backend/prisma/schema.prisma`
```prisma
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model Payment {
id Int @id @default(autoincrement())
rawMessage String @map("raw_message")
date DateTime?
type String?
card String?
recipient String?
amount Float?
currency String? @default("EUR")
balance Float?
source Source @default(INGEST)
status Status @default(UNPROCESSED)
tags Tag[]
notifiedAt DateTime? @map("notified_at")
notifyPhone String? @map("notify_phone")
debitBgn Float? @map("debit_bgn")
creditBgn Float? @map("credit_bgn")
transactionType String? @map("transaction_type")
payerAccount String? @map("payer_account")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@map("payments")
}
model Tag {
id Int @id @default(autoincrement())
name String @unique
color String @default("#6b7280")
payments Payment[]
@@map("tags")
}
enum Status { UNPROCESSED SENT SKIPPED }
enum Source { INGEST UPLOAD }
```
**Key decisions:**
- No `User` model — Authentik owns identity.
- `currency`: `EUR` for SMS ingest, `BGN` for CSV uploads.
- `debitBgn`, `creditBgn`, `transactionType`, `payerAccount`: nullable CSV-only columns; INGEST rows store nulls. Avoids a union query for the unified list view.
- `balance` is always null for CSV rows (DSK export does not include running balance).
- Fresh consolidated migration — no data migration from reference apps required.
---
## API Routes
| Method | Path | Auth | Description |
|--------|------|------|-------------|
| GET | /api/health | public | Health check |
| POST | /api/payments/ingest | public | SMS or structured ingest (source=INGEST) |
| GET | /api/payments | required | List with filters/sort/pagination (+ source filter) |
| GET | /api/payments/meta/tags | required | All tags |
| GET | /api/payments/meta/filters | required | Filter options incl. `sources` array |
| GET | /api/payments/:id | required | Single payment |
| PATCH | /api/payments/:id | required | Update status |
| DELETE | /api/payments/:id | required | Delete |
| POST | /api/payments/:id/send | required | Send notification |
| POST | /api/payments/:id/skip | required | Skip |
| POST | /api/payments/:id/tags | required | Add/upsert tag |
| DELETE | /api/payments/:id/tags/:tagId | required | Remove tag |
| POST | /api/upload/csv | required | DSK CSV file upload (source=UPLOAD) |
---
## Key Implementation Details
### auth.js (replaces entire old auth module)
```js
const PUBLIC_PATHS = new Set(['/api/health', '/api/payments/ingest']);
function authentikMiddleware(req, res, next) {
if (PUBLIC_PATHS.has(req.path)) return next();
const username = req.headers['x-authentik-username'];
if (!username) return res.status(401).json({ error: 'Unauthorized' });
req.user = {
username,
email: req.headers['x-authentik-email'] || null,
groups: (req.headers['x-authentik-groups'] || '').split(',').map(g => g.trim()).filter(Boolean),
};
next();
}
module.exports = { authentikMiddleware };
```
### csvParser.js (port of dskuploader.py)
- `iconv-lite` decodes buffer as cp1251 (DSK Bank export encoding), falls back to UTF-8
- `csv-parse` parses the decoded text with `columns: true`
- Columns: `Дата`, `Вид на трансакцията`, `Основание`, `Дебит BGN`, `Кредит BGN`, `Наредител/Получател`, `Номер сметка на наредителя / получателя`
- Card extraction: regex `/^\d{6}x{6}\d{4}$/` on first token of `Основание`
- Skips rows where `Вид на трансакцията === 'ТРАНСФЕР СОБСТВЕНИ СМЕТКИ'`
- Auto-tags via keyword rules (ЗАПЛАТА→Salary, LIDL→Groceries, NETFLIX→Subscriptions, etc.) — same logic as Python `generate_tags()`
- Returns `{ rows: PaymentData[], skipped: number, errors: string[] }`
### payments.js changes from payments-logger
1. Add `source: 'INGEST'` and `currency` to the `/ingest` create call
2. Add `source` to the `GET /` where clause filter
3. Add `sources` to `meta/filters` response
4. Currency-aware amount formatting in notification message
5. Remove all JWT/auth references (no `/auth/register`, `/auth/login`)
### upload.js (new)
- `multer` memory storage, max 10 files × 10 MB
- Calls `parseDskCsv(buffer)` per file
- Upserts tags via `prisma.tag.upsert` then connects
- Returns `{ imported, skipped, errors, payments[] }`
### Frontend changes
- **Delete**: `auth.js`, `AuthProvider.jsx`
- **main.jsx**: Remove `<AuthProvider>` wrapper
- **App.jsx**: Replace `authFetch` with plain `fetch` (Authentik session cookie travels automatically); logout → `window.location.href = '/outpost.goauthentik.io/sign_out'`; add "Payments" / "Upload CSV" tab toggle
- **FilterBar.jsx**: Add source `<select>` (All / SMS Ingest / CSV Upload); widen grid to 5 cols
- **PaymentTable.jsx**: Add `Source` column with `SMS` (indigo) / `CSV` (emerald) badge; show `${amount} ${currency}` in amount cell
- **UploadPanel.jsx** (new): Drag-and-drop zone + file list + import button + result summary with error accordion; calls `POST /api/upload/csv` with `FormData`
---
## Docker Compose
```yaml
services:
db:
image: postgres:16-alpine
environment: { POSTGRES_USER: finance, POSTGRES_PASSWORD: [PASSWORD] POSTGRES_DB: finance_hub }
volumes: [pgdata:/var/lib/postgresql/data]
healthcheck: { test: pg_isready -U finance -d finance_hub, interval: 5s }
backend:
build: ./backend
environment:
DATABASE_URL: [CONNECTION_STRING]
PORT: "3001"
NOTIFIER_URL: ${NOTIFIER_URL}
NOTIFIER_CHANNEL: ${NOTIFIER_CHANNEL:-viber}
NOTIFY_DEFAULT_PHONE: ${NOTIFY_DEFAULT_PHONE}
TZ: ${TZ:-Europe/Sofia}
ports: ["${BACKEND_PORT:-3001}:3001"]
depends_on: { db: { condition: service_healthy } }
frontend:
build: ./frontend
ports: ["${FRONTEND_PORT:-5175}:5173"]
depends_on: [backend]
volumes: { pgdata: }
```
**NPM setup:** Frontend port proxied through Authentik forward auth. Backend port exposed separately (unprotected) so the public `/api/payments/ingest` remains reachable by iOS Shortcuts / SMS gateways without login.
---
## Environment Variables (.env)
```bash
[ENV_SECRET]
NOTIFIER_URL=[URL_WITH_CREDENTIALS] @default(autoincrement())
rawMessage String @map("raw_message")
date DateTime?
type String?
card String?
recipient String?
amount Float?
currency String? @default("EUR")
balance Float?
source Source @default(INGEST)
status Status @default(UNPROCESSED)
tags Tag[]
notifiedAt DateTime? @map("notified_at")
notifyPhone String? @map("notify_phone")
debitBgn Float? @map("debit_bgn")
creditBgn Float? @map("credit_bgn")
transactionType String? @map("transaction_type")
payerAccount String? @map("payer_account")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@map("payments")
}
model Tag {
id Int @id @default(autoincrement())
name String @unique
color String @default("#6b7280")
payments Payment[]
@@map("tags")
}
enum Status {
UNPROCESSED
SENT
SKIPPED
}
enum Source {
INGEST
UPLOAD
}
Write
migration.sql
migration.sql
55 lines
-- CreateEnum
CREATE TYPE "Status" AS ENUM ('UNPROCESSED', 'SENT', 'SKIPPED');
CREATE TYPE "Source" AS ENUM ('INGEST', 'UPLOAD');
-- CreateTable
CREATE TABLE "payments" (
"id" SERIAL PRIMARY KEY,
"raw_message" TEXT NOT NULL,
"date" TIMESTAMP(3),
"type" TEXT,
"card" TEXT,
"recipient" TEXT,
"amount" DOUBLE PRECISION,
"currency" TEXT DEFAULT 'EUR',
"balance" DOUBLE PRECISION,
"source" "Source" NOT NULL DEFAULT 'INGEST',
"status" "Status" NOT NULL DEFAULT 'UNPROCESSED',
"notified_at" TIMESTAMP(3),
"notify_phone" TEXT,
"debit_bgn" DOUBLE PRECISION,
"credit_bgn" DOUBLE PRECISION,
"transaction_type" TEXT,
"payer_account" TEXT,
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP
);
-- CreateTable
CREATE TABLE "tags" (
"id" SERIAL PRIMARY KEY,
"name" TEXT NOT NULL,
"color" TEXT NOT NULL DEFAULT '#6b7280'
);
-- CreateUniqueIndex
CREATE UNIQUE INDEX "tags_name_key" ON "tags"("name");
-- CreateTable (M2M join)
CREATE TABLE "_PaymentToTag" (
"A" INTEGER NOT NULL,
"B" INTEGER NOT NULL,
CONSTRAINT "_PaymentToTag_AB_pkey" PRIMARY KEY ("A", "B")
);
CREATE INDEX "_PaymentToTag_B_index" ON "_PaymentToTag"("B");
-- AddForeignKey
ALTER TABLE "_PaymentToTag"
ADD CONSTRAINT "_PaymentToTag_A_fkey"
FOREIGN KEY ("A") REFERENCES "payments"("id") ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE "_PaymentToTag"
ADD CONSTRAINT "_PaymentToTag_B_fkey"
FOREIGN KEY ("B") REFERENCES "tags"("id") ON DELETE CASCADE ON UPDATE CASCADE;
Write
migration_lock.toml
migration_lock.toml
4 lines
# Please do not edit this file manually
# It should be added in your version-control system (e.g., Git)
provider = "postgresql"
Update Todos
Create folder structure and root config files
Write backend Prisma schema and migration
Write backend package.json and Dockerfile
Write backend src files (auth, parser, csvParser, index)
Write backend routes (payments.js, upload.js)
Write frontend config files
Write frontend React components
Build and verify with docker compose
Write
package.json
package.json
26 lines
{
"name": "finance-hub-backend",
"version": "1.0.0",
"main": "src/index.js",
"scripts": {
"start": "node src/index.js",
"dev": "nodemon src/index.js",
"prisma:generate": "prisma generate",
"prisma:migrate": "prisma migrate deploy"
},
"dependencies": {
"@prisma/client": "^5.22.0",
"cors": "^2.8.5",
"csv-parse": "^5.5.6",
"express": "^4.21.1",
"express-rate-limit": "^7.4.0",
"iconv-lite": "^0.6.3",
"morgan": "^1.10.0",
"multer": "^1.4.5-lts.1"
},
"devDependencies": {
"nodemon": "^3.1.7",
"prisma": "^5.22.0"
}
}
Write
Dockerfile
Dockerfile
18 lines
FROM node:20-alpine
RUN apk add --no-cache openssl
WORKDIR /app
COPY package.json package-lock.json* ./
RUN npm install
COPY prisma ./prisma
RUN npx prisma generate
COPY src ./src
EXPOSE 3001
CMD ["sh", "-c", "npx prisma migrate deploy && node src/index.js"]
Update Todos
Create folder structure and root config files
Write backend Prisma schema and migration
Write backend package.json and Dockerfile
Write backend src files (auth, parser, csvParser, index)
Write backend routes (payments.js, upload.js)
Write frontend config files
Write frontend React components
Build and verify with docker compose
Write
auth.js
auth.js
27 lines
const PUBLIC_PATHS = new Set([
'/api/health',
'/api/payments/ingest',
]);
function authentikMiddleware(req, res, next) {
if (PUBLIC_PATHS.has(req.path)) return next();
const username = req.headers['x-authentik-username'];
if (!username) {
return res.status(401).json({ error: 'Unauthorized — missing Authentik session' });
}
req.user = {
username,
email: req.headers['x-authentik-email'] || null,
groups: (req.headers['x-authentik-groups'] || '')
.split(',')
.map(g => g.trim())
.filter(Boolean),
};
next();
}
module.exports = { authentikMiddleware };
Write
parser.js
parser.js
104 lines
/**
* Parses SMS payment messages from Bulgarian banks (DSK Bank, etc.)
*
* Supported formats:
*
* POS / INTERNET / ECOM / P2P payment:
* DSK Bank. Na DD/MM/YYYY v HH:MM sa plateni AMOUNT CURRENCY s karta CARD na POS s adres: RECIPIENT. Nalichni: BALANCE CURRENCY.
*
* ATM withdrawal:
* DSK Bank. Na DD/MM/YYYY v HH:MM sa iztegleni AMOUNT CURRENCY s karta CARD ot ATM s adres: RECIPIENT. Nalichni: BALANCE CURRENCY.
*
* ATM utility payment (amount may include fee as AMOUNT/FEE):
* DSK Bank. Na DD/MM/YYYY v HH:MM sa plateni AMOUNT CURRENCY/FEE CURRENCY s karta CARD na ATM s adres:RECIPIENT. Nalichni: BALANCE CURRENCY.
*/
const LOCAL_TZ = process.env.TZ || 'Europe/Sofia';
/**
* Convert a local-timezone date/time to a UTC Date object.
* Uses Intl to resolve the actual UTC offset (DST-aware).
*/
function localToUtc(year, month, day, hour, minute) {
const naive = new Date(Date.UTC(year, month - 1, day, hour, minute, 0));
const formatter = new Intl.DateTimeFormat('en-US', {
timeZone: LOCAL_TZ,
year: 'numeric', month: '2-digit', day: '2-digit',
hour: '2-digit', minute: '2-digit', second: '2-digit',
hour12: false,
});
const parts = {};
formatter.formatToParts(naive).forEach(p => { parts[p.type] = p.value; });
const localAtNaive = new Date(Date.UTC(
parseInt(parts.year), parseInt(parts.month) - 1, parseInt(parts.day),
parseInt(parts.hour) % 24, parseInt(parts.minute), parseInt(parts.second),
));
const offsetMs = localAtNaive.getTime() - naive.getTime();
return new Date(Date.UTC(year, month - 1, day, hour, minute, 0) - offsetMs);
}
function parsePaymentSms(message) {
const result = {
rawMessage: message,
date: null,
type: null,
card: null,
recipient: null,
amount: null,
balance: null,
};
// Date and time: "Na DD/MM/YYYY v HH:MM"
const dateMatch = message.match(/Na (\d{2})\/(\d{2})\/(\d{4}) v (\d{2}):(\d{2})/i);
if (dateMatch) {
const [, day, month, year, hour, minute] = dateMatch;
result.date = localToUtc(
parseInt(year), parseInt(month), parseInt(day),
parseInt(hour), parseInt(minute),
);
}
// Card mask: "s karta 400915***4447" or "s karta 483890***7162"
const cardMatch = message.match(/s karta\s+([\d*]+)/i);
if (cardMatch) {
result.card = cardMatch[1];
}
// Transaction type: supports both prepositions
// "na POS" / "na ATM" / "na INTERNET" etc. (payment)
// "ot ATM" (withdrawal)
const typeMatch = message.match(/(?:na|ot)\s+(POS|ATM|INTERNET|ECOM|P2P)\b/i);
if (typeMatch) {
result.type = typeMatch[1].toUpperCase();
}
// Recipient address: "s adres: MERCHANT" or "s adres:MERCHANT" (no space variant)
const recipientMatch = message.match(/s adres:\s*([^.]+)\./i);
if (recipientMatch) {
result.recipient = recipientMatch[1].trim();
}
// Amount: handles both verbs and the AMOUNT/FEE suffix format
// "sa plateni 7.78 EUR"
// "sa iztegleni 400.00 EUR"
// "sa plateni 0.50 EUR/0.50 EUR" → captures 0.50 (the charged amount, ignoring fee)
const amountMatch = message.match(/sa (?:plateni|iztegleni)\s+([\d.,]+)\s+[A-Z]{3}/i);
if (amountMatch) {
result.amount = parseFloat(amountMatch[1].replace(',', '.'));
}
// Balance: "Nalichni: 2583.07 EUR."
const balanceMatch = message.match(/Nalichni:\s*([\d.,]+)\s+[A-Z]{3}/i);
if (balanceMatch) {
result.balance = parseFloat(balanceMatch[1].replace(',', '.'));
}
return result;
}
module.exports = { parsePaymentSms };
Write
csvParser.js
csvParser.js
175 lines
/**
* DSK Bank CSV parser — Node.js port of dskuploader.py
*
* DSK Bank exports use Windows-1251 (cp1251) encoding.
* Each row maps to a Payment record with source=UPLOAD, currency=BGN.
*/
const { parse } = require('csv-parse');
const iconv = require('iconv-lite');
const SKIP_TYPE = 'ТРАНСФЕР СОБСТВЕНИ СМЕТКИ';
const CARD_REGEX = /^\d{6}x{6}\d{4}$/;
const POS_REGEX = /^\s*ПЛАЩАНЕ\s+НА\s+ПОС\s+\d{2}\.\d{2}\.\d{4}\s+\d{2}:\d{2}/;
const COL = {
DATE: 'Дата',
TYPE: 'Вид на трансакцията',
REASON: 'Основание',
DEBIT: 'Дебит BGN',
CREDIT: 'Кредит BGN',
PAYEE: 'Наредител/Получател',
ACCT: 'Номер сметка на наредителя / получателя',
};
const TAG_RULES = [
['reason', 'ЗАПЛАТА', 'Salary'],
['reason', 'ТЕГЛЕНЕ НА ATM', 'ATM'],
['reason', 'ПЛАЩАНЕ ПО ЗАЕМ', 'Home Credit'],
['reason', 'АВТ.ТАКСА ОБСЛУЖВАНЕ', 'Bills'],
['transactionType', 'КОМУНАЛНИ УСЛУГИ', 'Bills'],
['payee', 'VIVACOM', 'Subscriptions'],
['payee', 'Google', 'Subscriptions'],
['payee', 'SkyShowtime', 'Subscriptions'],
['payee', 'NETFLIX', 'Subscriptions'],
['payee', 'LUKOIL', 'Bills'],
['payee', 'CityGate', 'Bills'],
['payee', 'CBA', 'Groceries'],
['payee', 'FANTASTICO', 'Groceries'],
['payee', 'LIDL', 'Groceries'],
];
function parseNum(val) {
if (val == null || val === '') return null;
if (typeof val === 'number') return isNaN(val) ? null : val;
const s = String(val).trim().replace(/\xa0/g, '').replace(/ /g, '').replace(',', '.');
const n = parseFloat(s);
return isNaN(n) ? null : n;
}
function parseDate(val) {
if (!val) return null;
const s = String(val).trim();
const m = s.match(/^(\d{2})\.(\d{2})\.(\d{4})$/);
if (m) {
return new Date(Date.UTC(parseInt(m[3]), parseInt(m[2]) - 1, parseInt(m[1])));
}
return null;
}
function processReasonAndCard(reason) {
if (!reason || typeof reason !== 'string') return { reason: '', card: null };
const parts = reason.trim().split(' ');
let card = null;
let cleanReason = reason.trim();
if (parts[0] && CARD_REGEX.test(parts[0])) {
card = parts[0];
cleanReason = parts.slice(1).join(' ').trim();
}
if (POS_REGEX.test(cleanReason)) {
const posParts = cleanReason.split('<br/>');
try {
const dateTime = posParts[0].split('ПОС ')[1];
cleanReason = `POS PAYMENT ${dateTime}`;
} catch (_) { /* keep original */ }
}
return { reason: cleanReason.replace(/\s+/g, ' ').trim(), card };
}
function generateTags(fields) {
const tags = new Set();
for (const [field, keyword, tagName] of TAG_RULES) {
if ((fields[field] || '').includes(keyword)) {
tags.add(tagName);
}
}
return Array.from(tags);
}
function processRow(row) {
const transactionType = (row[COL.TYPE] || '').trim();
if (transactionType === SKIP_TYPE) return null;
const { reason, card } = processReasonAndCard(row[COL.REASON]);
const payee = (row[COL.PAYEE] || '').trim();
const payerAccount = (row[COL.ACCT] || '').trim();
const debitBgn = parseNum(row[COL.DEBIT]);
const creditBgn = parseNum(row[COL.CREDIT]);
const date = parseDate(row[COL.DATE]);
const autoTags = generateTags({ reason, transactionType, payee, debitBgn, creditBgn });
const amount = debitBgn ?? creditBgn ?? null;
const rawMessage = [
row[COL.DATE] && `Date: ${row[COL.DATE]}`,
transactionType && `Type: ${transactionType}`,
payee && `Payee: ${payee}`,
debitBgn != null && `Debit: ${debitBgn} BGN`,
creditBgn != null && `Credit: ${creditBgn} BGN`,
].filter(Boolean).join(' | ');
return {
rawMessage,
date,
type: null,
card,
recipient: payee || null,
amount,
currency: 'BGN',
balance: null,
source: 'UPLOAD',
debitBgn,
creditBgn,
transactionType: transactionType || null,
payerAccount: payerAccount || null,
autoTags,
};
}
/**
* Parse a Buffer containing a DSK Bank CSV (cp1251 or UTF-8).
* Returns { rows, skipped, errors }.
*/
async function parseDskCsv(buffer) {
// Try cp1251 first (DSK Bank export encoding), fall back to UTF-8
let text = iconv.decode(buffer, 'cp1251');
if (!text.includes(COL.DATE)) {
text = buffer.toString('utf-8');
}
return new Promise((resolve, reject) => {
const rows = [];
const errors = [];
let skipped = 0;
const parser = parse(text, {
columns: true,
skip_empty_lines: true,
trim: true,
relax_column_count: true,
});
parser.on('readable', () => {
let record;
while ((record = parser.read()) !== null) {
try {
const row = processRow(record);
if (row === null) { skipped++; } else { rows.push(row); }
} catch (err) {
errors.push(err.message);
}
}
});
parser.on('error', reject);
parser.on('end', () => resolve({ rows, skipped, errors }));
});
}
module.exports = { parseDskCsv };
Write
index.js
index.js
39 lines
const express = require('express');
const cors = require('cors');
const morgan = require('morgan');
const rateLimit = require('express-rate-limit');
const { authentikMiddleware } = require('./auth');
const paymentsRouter = require('./routes/payments');
const uploadRouter = require('./routes/upload');
const app = express();
const PORT = process.env.PORT || 3001;
app.use(cors());
app.use(express.json({ limit: '16kb' }));
app.use(morgan('combined'));
// Rate-limit the public ingest endpoint before auth middleware
const ingestLimiter = rateLimit({
windowMs: 60 * 1000,
max: 200,
standardHeaders: true,
legacyHeaders: false,
message: { error: 'Too many requests, slow down' },
});
app.use('/api/payments/ingest', ingestLimiter);
// Authentik header auth (skips /api/health and /api/payments/ingest)
app.use(authentikMiddleware);
app.get('/api/health', (_req, res) => {
res.json({ status: 'ok', timestamp: new Date().toISOString() });
});
app.use('/api/payments', paymentsRouter);
app.use('/api/upload', uploadRouter);
app.listen(PORT, '[IP_ADDRESS]', () => {
console.log(`Finance Hub API running on port ${PORT}`);
});
Update Todos
Create folder structure and root config files
Write backend Prisma schema and migration
Write backend package.json and Dockerfile
Write backend src files (auth, parser, csvParser, index)
Write backend routes (payments.js, upload.js)
Write frontend config files
Write frontend React components
Build and verify with docker compose
Write
payments.js...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Explorer (⇧⌘E)","depth":19,"bounds":{"left":0.0,"top":0.047885075,"width":0.015957447,"height":0.03830806},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":true},{"role":"AXStaticText","text":"","depth":22,"bounds":{"left":0.0039893617,"top":0.057462092,"width":0.007978723,"height":0.01915403},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Search (⇧⌘F)","depth":19,"bounds":{"left":0.0,"top":0.08619314,"width":0.015957447,"height":0.03830806},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"bounds":{"left":0.0039893617,"top":0.09577015,"width":0.007978723,"height":0.01915403},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Source Control (⌃⇧G)","depth":19,"bounds":{"left":0.0,"top":0.1245012,"width":0.015957447,"height":0.03830806},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"bounds":{"left":0.0039893617,"top":0.13407822,"width":0.007978723,"height":0.01915403},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Run and Debug (⇧⌘D)","depth":19,"bounds":{"left":0.0,"top":0.16280925,"width":0.015957447,"height":0.03830806},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"bounds":{"left":0.0039893617,"top":0.17238627,"width":0.007978723,"height":0.01915403},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Remote Explorer","depth":19,"bounds":{"left":0.0,"top":0.20111732,"width":0.015957447,"height":0.03830806},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"bounds":{"left":0.0039893617,"top":0.21069433,"width":0.007978723,"height":0.01915403},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Extensions (⇧⌘X) - 2 require update","depth":19,"bounds":{"left":0.0,"top":0.23942538,"width":0.015957447,"height":0.03830806},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"bounds":{"left":0.0039893617,"top":0.2490024,"width":0.007978723,"height":0.01915403},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"2","depth":22,"bounds":{"left":0.009640957,"top":0.2601756,"width":0.0019946808,"height":0.008778931},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Claude Code","depth":19,"bounds":{"left":0.0,"top":0.27773345,"width":0.015957447,"height":0.03830806},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"Containers","depth":19,"bounds":{"left":0.0,"top":0.3160415,"width":0.015957447,"height":0.03830806},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"EXPLORER","depth":17,"bounds":{"left":0.022606382,"top":0.047885075,"width":0.018949468,"height":0.02793296},"on_screen":true,"role_description":"heading"},{"role":"AXStaticText","text":"EXPLORER","depth":18,"bounds":{"left":0.022606382,"top":0.056664005,"width":0.018949468,"height":0.0103751},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.022606382,"top":0.056664005,"width":0.0023271276,"height":0.0103751}},{"char_start":1,"char_count":7,"bounds":{"left":0.024933511,"top":0.056664005,"width":0.01662234,"height":0.0103751}}],"role_description":"text"},{"role":"AXButton","text":"Explorer Section: finance [SSH: nas]","depth":21,"bounds":{"left":0.015957447,"top":0.07581804,"width":0.09940159,"height":0.017557861},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.01662234,"top":0.07821229,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXHeading","text":"Explorer Section: finance [SSH: nas]","depth":22,"bounds":{"left":0.022606382,"top":0.07581804,"width":0.039228722,"height":0.017557861},"on_screen":true,"role_description":"heading"},{"role":"AXStaticText","text":"FINANCE [SSH: NAS]","depth":23,"bounds":{"left":0.022606382,"top":0.079010375,"width":0.039228722,"height":0.0103751},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.022606382,"top":0.07980846,"width":0.0023271276,"height":0.0103751}},{"char_start":1,"char_count":17,"bounds":{"left":0.024933511,"top":0.07980846,"width":0.036901597,"height":0.0103751}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.09577015,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"auth","depth":27,"bounds":{"left":0.025930852,"top":0.09577015,"width":0.008976064,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.096568234,"width":0.0023271276,"height":0.011971269}},{"char_start":1,"char_count":3,"bounds":{"left":0.02825798,"top":0.096568234,"width":0.0066489363,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.11332801,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"dsk-uploader","depth":27,"bounds":{"left":0.025930852,"top":0.11332801,"width":0.026928192,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.11412609,"width":0.0026595744,"height":0.011971269}},{"char_start":1,"char_count":11,"bounds":{"left":0.028590426,"top":0.11412609,"width":0.024268618,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.13088587,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"finance-hub","depth":27,"bounds":{"left":0.025930852,"top":0.13088587,"width":0.024268618,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.13168396,"width":0.0016622341,"height":0.011971269}},{"char_start":1,"char_count":10,"bounds":{"left":0.027593086,"top":0.13168396,"width":0.022938829,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.022273935,"top":0.14844373,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"backend","depth":27,"bounds":{"left":0.028590426,"top":0.14844373,"width":0.017287234,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.028590426,"top":0.14924182,"width":0.0026595744,"height":0.011971269}},{"char_start":1,"char_count":6,"bounds":{"left":0.03125,"top":0.14924182,"width":0.01462766,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.022273935,"top":0.1660016,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"frontend","depth":27,"bounds":{"left":0.028590426,"top":0.1660016,"width":0.017287234,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.028590426,"top":0.16679968,"width":0.0016622341,"height":0.011971269}},{"char_start":1,"char_count":7,"bounds":{"left":0.03025266,"top":0.16679968,"width":0.015625,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.021276595,"top":0.1819633,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":".env","depth":27,"bounds":{"left":0.028590426,"top":0.18355946,"width":0.00831117,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.028590426,"top":0.18435754,"width":0.0013297872,"height":0.011971269}},{"char_start":1,"char_count":3,"bounds":{"left":0.029920213,"top":0.18435754,"width":0.006981383,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.021276595,"top":0.19952115,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":".env.example","depth":27,"bounds":{"left":0.028590426,"top":0.20111732,"width":0.025930852,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.028590426,"top":0.2019154,"width":0.0013297872,"height":0.011971269}},{"char_start":1,"char_count":11,"bounds":{"left":0.029920213,"top":0.2019154,"width":0.024933511,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.021276595,"top":0.21707901,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":".gitignore","depth":27,"bounds":{"left":0.028590426,"top":0.21867518,"width":0.018949468,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.028590426,"top":0.21947326,"width":0.0013297872,"height":0.011971269}},{"char_start":1,"char_count":9,"bounds":{"left":0.029920213,"top":0.21947326,"width":0.017952127,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.021276595,"top":0.23463687,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"docker-compose.yml","depth":27,"bounds":{"left":0.028590426,"top":0.23623304,"width":0.042220745,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.028590426,"top":0.23703113,"width":0.0026595744,"height":0.011971269}},{"char_start":1,"char_count":17,"bounds":{"left":0.03125,"top":0.23703113,"width":0.03956117,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.25379092,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"payments-logger","depth":27,"bounds":{"left":0.025930852,"top":0.25379092,"width":0.034574468,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.254589,"width":0.0026595744,"height":0.011971269}},{"char_start":1,"char_count":14,"bounds":{"left":0.028590426,"top":0.254589,"width":0.031914894,"height":0.011971269}}],"role_description":"text"},{"role":"AXButton","text":"Outline Section","depth":21,"bounds":{"left":0.015957447,"top":0.9473264,"width":0.09940159,"height":0.017557861},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.01662234,"top":0.9497207,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXHeading","text":"OUTLINE","depth":22,"bounds":{"left":0.022606382,"top":0.9473264,"width":0.01662234,"height":0.017557861},"on_screen":true,"role_description":"heading"},{"role":"AXStaticText","text":"OUTLINE","depth":23,"bounds":{"left":0.022606382,"top":0.95131683,"width":0.01662234,"height":0.0103751},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.022606382,"top":0.95131683,"width":0.0029920214,"height":0.0103751}},{"char_start":1,"char_count":6,"bounds":{"left":0.025598405,"top":0.95131683,"width":0.013630319,"height":0.0103751}}],"role_description":"text"},{"role":"AXButton","text":"Timeline Section","depth":21,"bounds":{"left":0.015957447,"top":0.9648843,"width":0.09940159,"height":0.017557861},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.01662234,"top":0.96727854,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXHeading","text":"TIMELINE","depth":22,"bounds":{"left":0.022606382,"top":0.9648843,"width":0.01761968,"height":0.017557861},"on_screen":true,"role_description":"heading"},{"role":"AXStaticText","text":"TIMELINE","depth":23,"bounds":{"left":0.022606382,"top":0.9688747,"width":0.01761968,"height":0.0103751},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.022606382,"top":0.9688747,"width":0.0026595744,"height":0.0103751}},{"char_start":1,"char_count":7,"bounds":{"left":0.025265958,"top":0.9688747,"width":0.015292553,"height":0.0103751}}],"role_description":"text"},{"role":"AXRadioButton","text":"docker-compose.yml, Editor Group 1","depth":28,"bounds":{"left":0.11569149,"top":0.047885075,"width":0.0625,"height":0.02793296},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXRadioButton","text":".env, Editor Group 1","depth":28,"bounds":{"left":0.17785904,"top":0.047885075,"width":0.040226065,"height":0.02793296},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":29,"bounds":{"left":0.14527926,"top":0.07821229,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"version: '3.8'\n\nservices:\n db:\n image: postgres:16-alpine\n restart: unless-stopped\n environment:\n POSTGRES_USER: finance\n POSTGRES_PASSWORD: ${DB_PASSWORD}\n POSTGRES_DB: finance_hub\n volumes:\n - pgdata:/var/lib/postgresql/data\n healthcheck:\n test: [\"CMD-SHELL\", \"pg_isready -U finance -d finance_hub\"]\n interval: 5s\n timeout: 5s\n retries: 5\n\n backend:\n build: ./backend\n restart: unless-stopped\n environment:\n DATABASE_URL: postgresql://finance:${DB_PASSWORD}@db:5432/finance_hub\n PORT: \"3001\"\n NOTIFIER_URL: ${NOTIFIER_URL}\n NOTIFIER_CHANNEL: ${NOTIFIER_CHANNEL:-viber}\n NOTIFY_DEFAULT_PHONE: ${NOTIFY_DEFAULT_PHONE}\n TZ: ${TZ:-Europe/Sofia}\n ports:\n - \"${BACKEND_PORT:-3001}:3001\"\n depends_on:\n db:\n condition: service_healthy\n\n frontend:\n build: ./frontend\n restart: unless-stopped\n ports:\n - \"${FRONTEND_PORT:-5175}:5173\"\n depends_on:\n - backend\n\nvolumes:\n pgdata:","depth":28,"bounds":{"left":0.13763298,"top":0.26097366,"width":0.18018617,"height":0.014365523},"on_screen":true,"value":"version: '3.8'\n\nservices:\n db:\n image: postgres:16-alpine\n restart: unless-stopped\n environment:\n POSTGRES_USER: finance\n POSTGRES_PASSWORD: ${DB_PASSWORD}\n POSTGRES_DB: finance_hub\n volumes:\n - pgdata:/var/lib/postgresql/data\n healthcheck:\n test: [\"CMD-SHELL\", \"pg_isready -U finance -d finance_hub\"]\n interval: 5s\n timeout: 5s\n retries: 5\n\n backend:\n build: ./backend\n restart: unless-stopped\n environment:\n DATABASE_URL: postgresql://finance:${DB_PASSWORD}@db:5432/finance_hub\n PORT: \"3001\"\n NOTIFIER_URL: ${NOTIFIER_URL}\n NOTIFIER_CHANNEL: ${NOTIFIER_CHANNEL:-viber}\n NOTIFY_DEFAULT_PHONE: ${NOTIFY_DEFAULT_PHONE}\n TZ: ${TZ:-Europe/Sofia}\n ports:\n - \"${BACKEND_PORT:-3001}:3001\"\n depends_on:\n db:\n condition: service_healthy\n\n frontend:\n build: ./frontend\n restart: unless-stopped\n ports:\n - \"${FRONTEND_PORT:-5175}:5173\"\n depends_on:\n - backend\n\nvolumes:\n pgdata:","role_description":"editor","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"version: '3.8'\n\nservices:\n db:\n image: postgres:16-alpine\n restart: unless-stopped\n environment:\n POSTGRES_USER: finance\n POSTGRES_PASSWORD: ${DB_PASSWORD}\n POSTGRES_DB: finance_hub\n volumes:\n - pgdata:/var/lib/postgresql/data\n healthcheck:\n test: [\"CMD-SHELL\", \"pg_isready -U finance -d finance_hub\"]\n interval: 5s\n timeout: 5s\n retries: 5\n\n backend:\n build: ./backend\n restart: unless-stopped\n environment:\n DATABASE_URL: postgresql://finance:${DB_PASSWORD}@db:5432/finance_hub\n PORT: \"3001\"\n NOTIFIER_URL: ${NOTIFIER_URL}\n NOTIFIER_CHANNEL: ${NOTIFIER_CHANNEL:-viber}\n NOTIFY_DEFAULT_PHONE: ${NOTIFY_DEFAULT_PHONE}\n TZ: ${TZ:-Europe/Sofia}\n ports:\n - \"${BACKEND_PORT:-3001}:3001\"\n depends_on:\n db:\n condition: service_healthy\n\n frontend:\n build: ./frontend\n restart: unless-stopped\n ports:\n - \"${FRONTEND_PORT:-5175}:5173\"\n depends_on:\n - backend\n\nvolumes:\n pgdata:","depth":29,"bounds":{"left":0.13763298,"top":0.26097366,"width":0.18018617,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Design new payment-logge…, Editor Group 2","depth":28,"bounds":{"left":0.5578458,"top":0.047885075,"width":0.07912234,"height":0.02793296},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXButton","text":"remote SSH: nas","depth":16,"bounds":{"left":0.0006648936,"top":0.98244214,"width":0.028590426,"height":0.01755786},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":17,"bounds":{"left":0.0033244682,"top":0.9848364,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"SSH: nas","depth":17,"bounds":{"left":0.008643617,"top":0.9856345,"width":0.017952127,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"No Problems","depth":16,"bounds":{"left":0.03025266,"top":0.98244214,"width":0.022606382,"height":0.01755786},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":17,"bounds":{"left":0.031914894,"top":0.9848364,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"0","depth":17,"bounds":{"left":0.03723404,"top":0.9856345,"width":0.004986702,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":17,"bounds":{"left":0.041888297,"top":0.9848364,"width":0.0056515955,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"0","depth":17,"bounds":{"left":0.04720745,"top":0.9856345,"width":0.0039893617,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"No Ports Forwarded","depth":16,"bounds":{"left":0.054521278,"top":0.98244214,"width":0.012632979,"height":0.01755786},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":17,"bounds":{"left":0.05618351,"top":0.9848364,"width":0.0056515955,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"0","depth":17,"bounds":{"left":0.061502658,"top":0.9856345,"width":0.0039893617,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Notifications","depth":16,"bounds":{"left":0.9886968,"top":0.98244214,"width":0.010638298,"height":0.01755786},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sign In","depth":16,"bounds":{"left":0.9650931,"top":0.98244214,"width":0.022606382,"height":0.01755786},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":17,"bounds":{"left":0.96675533,"top":0.9848364,"width":0.0056515955,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Sign In","depth":17,"bounds":{"left":0.97207445,"top":0.9856345,"width":0.013962766,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Info: Setting up SSH Host nas: Setting up SSH tunnel","depth":12,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Design new payment-logger and dsk-uploader hybrid app","depth":19,"bounds":{"left":0.55984044,"top":0.08060654,"width":0.099734046,"height":0.022346368},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Session history","depth":19,"bounds":{"left":0.9780585,"top":0.08060654,"width":0.00930851,"height":0.022346368},"on_screen":true,"help_text":"Session history","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New session","depth":19,"bounds":{"left":0.9886968,"top":0.08060654,"width":0.00930851,"height":0.022346368},"on_screen":true,"help_text":"New session","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Message actions","depth":24,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"payments.js","depth":23,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"payments.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ets create a new app that should be combination of payment-logger and dsk-uploader. It should have authorization via authentik (auth folder). All three folders (payment-logger, dsk-uploader and auth) are just refference these will be removed later. Auth project is separated it lives on its own. First reveiw them and see how these should be combined. It will be whole new app (also the folder name). Think very carefully of whatr these two apps do and how cold they be combined. THerer should be common db and uploader should store data the same way the /ingest does. It should be properly marked in UI if it is upload or ingest or both. FIrst think of tech stack and plan carefully.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":23,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Thinking","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"I'll explore all three reference projects in parallel to understand their structure before planning.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Agent:","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Explore payment-logger app structure and functionality","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Explore the /volume2/docker/finance/payments-logger directory thoroughly. I need to understand:\n1. Tech stack (frontend framework, backend framework, database)\n2. What the app does - its core purpose and features\n3. Database schema - all tables, relationships\n4. API routes - all endpoints, their purpose and request/response shapes\n5. How data flows (ingest, storage, retrieval)\n6. Any auth/middleware setup\n7. Docker/deployment setup\n8. Key files and their roles\n\nReport with: directory structure, tech stack summary, database schema details, all API endpoints listed, UI features, and how data is ingested. Be thorough on the /ingest endpoint specifically.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Agent:","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Explore dsk-uploader app structure and functionality","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Explore the /volume2/docker/finance/dsk-uploader directory thoroughly. I need to understand:\n1. Tech stack (frontend framework, backend framework, database)\n2. What the app does - its core purpose and features\n3. Database schema - all tables, relationships\n4. API routes - all endpoints, their purpose and request/response shapes\n5. How file uploads work - what files, what format, how parsed\n6. Any auth/middleware setup\n7. Docker/deployment setup\n8. Key files and their roles\n\nReport with: directory structure, tech stack summary, database schema details, all API endpoints listed, UI features, how file upload parsing works, and what data is extracted from uploads. Be very thorough about the data model and what fields are stored.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Agent:","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Explore auth folder and authentik integration","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Explore the /volume2/docker/finance/auth directory thoroughly. I need to understand:\n1. What auth system is being used (Authentik)\n2. How authentication/authorization is implemented - OAuth2, OIDC, session tokens, JWT?\n3. Middleware - how is auth enforced on routes?\n4. Any frontend auth flow - login redirect, token handling, protected routes\n5. Environment variables related to auth\n6. Docker/deployment setup for the auth service itself\n7. Any example of how other apps integrate with this auth\n\nReport with: directory structure, auth flow description, middleware code, environment variable names, and integration patterns. This is a reference for building auth into a new combined app.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Message actions","depth":24,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"payments.js","depth":23,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"payments.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"continue","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":23,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Thinking","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Launching parallel exploration of all three reference projects.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Agent:","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Explore payment-logger app structure","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Explore the /volume2/docker/finance/payments-logger directory thoroughly. I need to understand:\n1. Full directory structure (tree)\n2. Tech stack (frontend framework, backend framework, database, etc.)\n3. What the app does - its core functionality\n4. How data is ingested (look at /ingest route especially)\n5. Database schema (what tables/collections exist)\n6. API routes and their purposes\n7. Frontend pages and components\n8. Docker setup\n9. Any auth/session handling\n\nPlease read key files: package.json files, main entry points, route files, database schema files, docker-compose.yml, and any frontend components. Be thorough - I need a complete picture to plan a new combined app.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Agent:","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Explore dsk-uploader app structure","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Explore the /volume2/docker/finance/dsk-uploader directory thoroughly. I need to understand:\n1. Full directory structure (tree)\n2. Tech stack (frontend framework, backend framework, database, etc.)\n3. What the app does - its core functionality\n4. How file uploads work (what format, what processing happens)\n5. Database schema (what tables/collections exist)\n6. API routes and their purposes\n7. Frontend pages and components\n8. Docker setup\n9. Any auth/session handling\n\nPlease read key files: package.json files, main entry points, route files, database schema files, docker-compose.yml, and any frontend components. Be thorough - I need a complete picture to plan a new combined app.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Agent:","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Explore auth project structure","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Explore the /volume2/docker/finance/auth directory thoroughly. I need to understand:\n1. Full directory structure (tree)\n2. What authentication system is used (authentik integration details)\n3. How OAuth/OIDC flow works\n4. Any middleware or helper functions for protecting routes\n5. Session management approach\n6. How frontend handles auth state\n7. Any example of how other apps integrate with this auth system\n8. Docker setup and environment variables\n\nPlease read all files carefully - this auth system will be integrated into a new combined app. I need to understand exactly how to use it.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":23,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Thinking","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Now I have a complete picture of all three. Let me design the plan.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Agent:","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Design combined app architecture","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Design a detailed implementation plan for a new combined web app that merges two existing applications. Here is full context:\n\n---\n\n## App 1: payments-logger (Node.js)\n- **Purpose**: Ingest Bulgarian bank SMS → parse → store in PostgreSQL → review/tag/notify in React UI\n- **Stack**: Node.js 20 + Express + Prisma 5 + PostgreSQL 16 + React 18 + Vite + Tailwind CSS\n- **Auth**: Custom JWT (bcryptjs + jose), tokens in localStorage\n- **Ingest**: POST /api/payments/ingest (public) — SMS text OR structured JSON (Apple Wallet)\n- **Schema** (PostgreSQL via Prisma):\n - `payments` table: id, raw_message, date, type (POS/ATM/INTERNET/ECOM/P2P/WALLET), card, recipient, amount, balance, status (UNPROCESSED/SENT/SKIPPED), notifyPhone, notifiedAt, created_at, updated_at\n - `tags` table: id, name, color — M2M with payments via `_PaymentToTag`\n - `users` table: id, username, hashed_password (this will be REMOVED)\n- **UI**: Single-page React app — PaymentTable (sortable, filterable, taggable), FilterBar, status actions (send/skip), notification system\n- **Parser** (backend/src/parser.js): Regex parser for Bulgarian DSK Bank SMS, extracts date/time (DD/MM/YYYY HH:MM), card mask, transaction type, recipient, amount, balance\n\n## App 2: dsk-uploader (Python/Flask)\n- **Purpose**: Upload DSK bank CSV exports → parse/normalize → upload to Notion database\n- **Stack**: Python 3.11 + Flask + Pandas + Custom Notion SDK + Bootstrap 5\n- **Auth**: None (open)\n- **CSV format** (DSK Bank Bulgarian format, columns):\n - `Дата` (date, DD.MM.YYYY)\n - `Вид на трансакцията` (transaction type, Bulgarian)\n - `Основание` (reason/description — contains card number regex: `^\\d{6}x{6}\\d{4}$`)\n - `Дебит BGN` (debit amount, may be empty)\n - `Кредит BGN` (credit amount, may be empty)\n - `Наредител/Получател` (orderer/recipient name)\n - `Номер сметка на наредителя / получателя` (account number)\n- **Processing**: merge multiple CSVs, normalize dates, extract card numbers from reason via regex, auto-generate tags (keyword heuristics: ЗАПЛАТА→Salary, NETFLIX→Subscriptions, etc.), filter internal transfers\n- **Output**: Notion database pages (this will be REPLACED with local PostgreSQL)\n\n## App 3: auth (Authentik)\n- **Mode**: Proxy mode via NPM (forward auth)\n- **How it works**: NPM intercepts all requests, calls Authentik outpost's auth endpoint. On success, NPM injects headers into proxied request:\n - `X-authentik-username` \n - `X-authentik-email`\n - `X-authentik-groups`\n- **No code integration needed** in the app itself — just trust these headers from NPM\n- **Logout**: Redirect user to `/outpost.goauthentik.io/sign_out`\n\n---\n\n## What the New Combined App Must Do\n\n1. **Single PostgreSQL database** for all transactions\n2. **SMS Ingest** (public endpoint) — same as payments-logger /ingest, source=INGEST\n3. **CSV Upload** (authenticated) — parse DSK CSV files, store transactions with source=UPLOAD into the same DB schema\n4. **Unified UI** — show all payments in one table regardless of source\n5. **Source indicator** in UI — badge showing \"INGEST\", \"UPLOAD\", or \"BOTH\" (if duplicate detection added)\n6. **Source filter** in FilterBar — filter by All/Ingest/Upload\n7. **Authentik auth** — remove custom JWT entirely; trust X-authentik-* headers from NPM\n8. **All existing payments-logger features**: tagging, send notification, skip, status tracking, filters, sorting, pagination\n9. **Remove Notion dependency entirely** — all data stays in local PostgreSQL\n\n---\n\n## Technical Constraints\n\n- Keep Node.js backend (not Python) — extend payments-logger's stack\n- CSV parsing: use `csv-parse` npm package (handles encoding, streaming)\n- File upload: use `multer` npm middleware\n- Auth middleware: read X-authentik-username header, 401 if missing (but /api/payments/ingest stays public)\n- Add `source` enum field (INGEST/UPLOAD) to payments schema\n- Add `currency` field (EUR for SMS ingest, BGN for CSV uploads) — or just store as-is\n- Remove `users` table from schema\n\n---\n\n## Please Design\n\n1. Complete folder structure for the new app (suggest name: \"finance-hub\" or similar — note this is a placeholder, user will confirm)\n2. Prisma schema with new fields (`source`, `currency`)\n3. All backend API routes\n4. CSV parser design in Node.js (port of the Python logic)\n5. Authentik auth middleware\n6. Frontend component structure (React) — what's reused from payments-logger, what's new\n7. Docker Compose setup\n8. Environment variables needed\n9. Step-by-step implementation order\n10. Verification checklist\n\nBe specific about file paths and code structure. This will be used to write actual implementation code.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":23,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Thinking","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Good plan. Let me ask the one thing I need before writing the final plan.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskUserQuestion","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"User has answered your questions: \"What should the new combined app be called? This will be the folder name under /volume2/docker/finance/ and the app branding.\"=\"finance-hub\". You can now continue with the user's answers in mind.","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":23,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Thinking","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Writing the final plan now.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":23,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Thinking","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"ets-create-a-new-generic-sun.md","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"ets-create-a-new-generic-sun.md","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"326 lines","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"# finance-hub — Implementation Plan\n\n## Context\n\nTwo separate finance apps exist as references and will be retired:\n- **payments-logger** (Node.js/React): Ingests Bulgarian bank SMS notifications, stores payments in PostgreSQL, provides a review/tag/notify UI.\n- **dsk-uploader** (Python/Flask): Uploads DSK bank CSV exports, parses them, sends to Notion.\n\nThe new app **finance-hub** (`/volume2/docker/finance/finance-hub/`) replaces both with a single unified system: all transactions (SMS-ingested and CSV-uploaded) land in one PostgreSQL database and one React UI. Authentication is delegated entirely to Authentik (proxy mode via NPM — no custom JWT).\n\n---\n\n## Tech Stack\n\n| Layer | Choice | Rationale |\n|-------|--------|-----------|\n| Backend | Node.js 20 + Express + Prisma 5 | Extends payments-logger; no Python needed |\n| CSV parsing | `csv-parse` + `iconv-lite` | Handles Bulgarian cp1251 encoding, RFC4180 quoted fields |\n| File upload | `multer` (memory storage) | Bank CSVs are small (<500 KB), no disk cleanup needed |\n| Database | PostgreSQL 16 | Same as payments-logger |\n| Frontend | React 18 + Vite + Tailwind CSS + Lucide React | Same as payments-logger |\n| Auth | Authentik proxy via NPM headers | No custom JWT; removes users table entirely |\n| Container | Docker Compose | Same pattern as both reference apps |\n\n**Removed vs payments-logger:** `bcryptjs`, `jose`, `users` table, login form, JWT storage. \n**Removed vs dsk-uploader:** Python/Flask, Pandas, Notion SDK, all Notion references. \n**Added:** `csv-parse`, `iconv-lite`, `multer`, `source` + `currency` fields, `UploadPanel` component.\n\n---\n\n## Folder Structure\n\n```\n/volume2/docker/finance/finance-hub/\n├── docker-compose.yml\n├── .env\n├── .env.example\n├── .gitignore\n├── backend/\n│ ├── Dockerfile\n│ ├── package.json\n│ ├── prisma/\n│ │ ├── schema.prisma\n│ │ └── migrations/\n│ │ ├── migration_lock.toml\n│ │ └── 20260508_init/\n│ │ └── migration.sql\n│ └── src/\n│ ├── index.js ← entry point (Authentik middleware wired here)\n│ ├── auth.js ← Authentik header middleware (replaces JWT auth)\n│ ├── parser.js ← SMS parser (copy verbatim from payments-logger)\n│ ├── csvParser.js ← NEW: DSK CSV parser (port of Python dskuploader.py)\n│ └── routes/\n│ ├── payments.js ← existing routes + source/currency additions\n│ └── upload.js ← NEW: POST /api/upload/csv\n└── frontend/\n ├── Dockerfile\n ├── package.json\n ├── vite.config.js\n ├── tailwind.config.js\n ├── postcss.config.js\n ├── index.html\n └── src/\n ├── main.jsx ← remove AuthProvider wrapper\n ├── index.css\n ├── App.jsx ← remove auth state, add Upload tab toggle\n └── components/\n ├── FilterBar.jsx ← add source filter select\n ├── PaymentTable.jsx ← add Source badge column + currency display\n ├── PaymentCard.jsx ← minor source badge addition\n ├── PaymentList.jsx ← unchanged\n └── UploadPanel.jsx ← NEW: drag-and-drop CSV upload UI\n```\n\n---\n\n## Database Schema (Prisma)\n\nFile: `backend/prisma/schema.prisma`\n\n```prisma\ngenerator client {\n provider = \"prisma-client-js\"\n}\n\ndatasource db {\n provider = \"postgresql\"\n url = env(\"DATABASE_URL\")\n}\n\nmodel Payment {\n id Int @id @default(autoincrement())\n rawMessage String @map(\"raw_message\")\n date DateTime?\n type String?\n card String?\n recipient String?\n amount Float?\n currency String? @default(\"EUR\")\n balance Float?\n source Source @default(INGEST)\n status Status @default(UNPROCESSED)\n tags Tag[]\n notifiedAt DateTime? @map(\"notified_at\")\n notifyPhone String? @map(\"notify_phone\")\n debitBgn Float? @map(\"debit_bgn\")\n creditBgn Float? @map(\"credit_bgn\")\n transactionType String? @map(\"transaction_type\")\n payerAccount String? @map(\"payer_account\")\n createdAt DateTime @default(now()) @map(\"created_at\")\n updatedAt DateTime @updatedAt @map(\"updated_at\")\n\n @@map(\"payments\")\n}\n\nmodel Tag {\n id Int @id @default(autoincrement())\n name String @unique\n color String @default(\"#6b7280\")\n payments Payment[]\n\n @@map(\"tags\")\n}\n\nenum Status { UNPROCESSED SENT SKIPPED }\nenum Source { INGEST UPLOAD }\n```\n\n**Key decisions:**\n- No `User` model — Authentik owns identity.\n- `currency`: `EUR` for SMS ingest, `BGN` for CSV uploads.\n- `debitBgn`, `creditBgn`, `transactionType`, `payerAccount`: nullable CSV-only columns; INGEST rows store nulls. Avoids a union query for the unified list view.\n- `balance` is always null for CSV rows (DSK export does not include running balance).\n- Fresh consolidated migration — no data migration from reference apps required.\n\n---\n\n## API Routes\n\n| Method | Path | Auth | Description |\n|--------|------|------|-------------|\n| GET | /api/health | public | Health check |\n| POST | /api/payments/ingest | public | SMS or structured ingest (source=INGEST) |\n| GET | /api/payments | required | List with filters/sort/pagination (+ source filter) |\n| GET | /api/payments/meta/tags | required | All tags |\n| GET | /api/payments/meta/filters | required | Filter options incl. `sources` array |\n| GET | /api/payments/:id | required | Single payment |\n| PATCH | /api/payments/:id | required | Update status |\n| DELETE | /api/payments/:id | required | Delete |\n| POST | /api/payments/:id/send | required | Send notification |\n| POST | /api/payments/:id/skip | required | Skip |\n| POST | /api/payments/:id/tags | required | Add/upsert tag |\n| DELETE | /api/payments/:id/tags/:tagId | required | Remove tag |\n| POST | /api/upload/csv | required | DSK CSV file upload (source=UPLOAD) |\n\n---\n\n## Key Implementation Details\n\n### auth.js (replaces entire old auth module)\n```js\nconst PUBLIC_PATHS = new Set(['/api/health', '/api/payments/ingest']);\n\nfunction authentikMiddleware(req, res, next) {\n if (PUBLIC_PATHS.has(req.path)) return next();\n const username = req.headers['x-authentik-username'];\n if (!username) return res.status(401).json({ error: 'Unauthorized' });\n req.user = {\n username,\n email: req.headers['x-authentik-email'] || null,\n groups: (req.headers['x-authentik-groups'] || '').split(',').map(g => g.trim()).filter(Boolean),\n };\n next();\n}\nmodule.exports = { authentikMiddleware };\n```\n\n### csvParser.js (port of dskuploader.py)\n- `iconv-lite` decodes buffer as cp1251 (DSK Bank export encoding), falls back to UTF-8\n- `csv-parse` parses the decoded text with `columns: true`\n- Columns: `Дата`, `Вид на трансакцията`, `Основание`, `Дебит BGN`, `Кредит BGN`, `Наредител/Получател`, `Номер сметка на наредителя / получателя`\n- Card extraction: regex `/^\\d{6}x{6}\\d{4}$/` on first token of `Основание`\n- Skips rows where `Вид на трансакцията === 'ТРАНСФЕР СОБСТВЕНИ СМЕТКИ'`\n- Auto-tags via keyword rules (ЗАПЛАТА→Salary, LIDL→Groceries, NETFLIX→Subscriptions, etc.) — same logic as Python `generate_tags()`\n- Returns `{ rows: PaymentData[], skipped: number, errors: string[] }`\n\n### payments.js changes from payments-logger\n1. Add `source: 'INGEST'` and `currency` to the `/ingest` create call\n2. Add `source` to the `GET /` where clause filter\n3. Add `sources` to `meta/filters` response\n4. Currency-aware amount formatting in notification message\n5. Remove all JWT/auth references (no `/auth/register`, `/auth/login`)\n\n### upload.js (new)\n- `multer` memory storage, max 10 files × 10 MB\n- Calls `parseDskCsv(buffer)` per file\n- Upserts tags via `prisma.tag.upsert` then connects\n- Returns `{ imported, skipped, errors, payments[] }`\n\n### Frontend changes\n- **Delete**: `auth.js`, `AuthProvider.jsx`\n- **main.jsx**: Remove `<AuthProvider>` wrapper\n- **App.jsx**: Replace `authFetch` with plain `fetch` (Authentik session cookie travels automatically); logout → `window.location.href = '/outpost.goauthentik.io/sign_out'`; add \"Payments\" / \"Upload CSV\" tab toggle\n- **FilterBar.jsx**: Add source `<select>` (All / SMS Ingest / CSV Upload); widen grid to 5 cols\n- **PaymentTable.jsx**: Add `Source` column with `SMS` (indigo) / `CSV` (emerald) badge; show `${amount} ${currency}` in amount cell\n- **UploadPanel.jsx** (new): Drag-and-drop zone + file list + import button + result summary with error accordion; calls `POST /api/upload/csv` with `FormData`\n\n---\n\n## Docker Compose\n\n```yaml\nservices:\n db:\n image: postgres:16-alpine\n environment: { POSTGRES_USER: finance, POSTGRES_PASSWORD: ${DB_PASSWORD}, POSTGRES_DB: finance_hub }\n volumes: [pgdata:/var/lib/postgresql/data]\n healthcheck: { test: pg_isready -U finance -d finance_hub, interval: 5s }\n\n backend:\n build: ./backend\n environment:\n DATABASE_URL: postgresql://finance:${DB_PASSWORD}@db:5432/finance_hub\n PORT: \"3001\"\n NOTIFIER_URL: ${NOTIFIER_URL}\n NOTIFIER_CHANNEL: ${NOTIFIER_CHANNEL:-viber}\n NOTIFY_DEFAULT_PHONE: ${NOTIFY_DEFAULT_PHONE}\n TZ: ${TZ:-Europe/Sofia}\n ports: [\"${BACKEND_PORT:-3001}:3001\"]\n depends_on: { db: { condition: service_healthy } }\n\n frontend:\n build: ./frontend\n ports: [\"${FRONTEND_PORT:-5175}:5173\"]\n depends_on: [backend]\n\nvolumes: { pgdata: }\n```\n\n**NPM setup:** Frontend port proxied through Authentik forward auth. Backend port exposed separately (unprotected) so the public `/api/payments/ingest` remains reachable by iOS Shortcuts / SMS gateways without login.\n\n---\n\n## Environment Variables (.env)\n\n```bash\nDB_PASSWORD=change_me\nNOTIFIER_URL=https://notifier.lakylak.xyz\nNOTIFIER_CHANNEL=viber\nNOTIFY_DEFAULT_PHONE=+359000000000\nTZ=Europe/Sofia\nBACKEND_PORT=3001\nFRONTEND_PORT=5175\n```\n\nRemoved vs payments-logger: `JWT_SECRET`, `JWT_EXPIRE_MINUTES`.\n\n---\n\n## Implementation Order\n\n1. Create folder structure and write `docker-compose.yml`, `.env.example`, `.gitignore`\n2. Write `backend/prisma/schema.prisma` and migration SQL\n3. Write `backend/package.json` (add `csv-parse`, `iconv-lite`, `multer`; remove `bcryptjs`, `jose`)\n4. Write `backend/Dockerfile`\n5. Write `backend/src/auth.js` (Authentik middleware)\n6. Copy `backend/src/parser.js` verbatim from payments-logger\n7. Write `backend/src/csvParser.js` (Python port)\n8. Write `backend/src/routes/upload.js`\n9. Write `backend/src/routes/payments.js` (from payments-logger + 5 changes listed above)\n10. Write `backend/src/index.js`\n11. Copy frontend base from payments-logger; delete `auth.js` + `AuthProvider.jsx`\n12. Update `main.jsx`, `App.jsx`, `FilterBar.jsx`, `PaymentTable.jsx`\n13. Write `frontend/src/components/UploadPanel.jsx`\n14. Update `frontend/vite.config.js`\n15. `docker compose build && docker compose up -d`\n16. Run verification checklist\n\n---\n\n## Verification\n\n**Schema**\n- `payments` table has `source`, `currency`, `debit_bgn`, `credit_bgn`, `transaction_type`, `payer_account`\n- No `users` table; `Source` enum exists\n\n**Auth**\n- `GET /api/payments` → 401 without `x-authentik-username` header\n- `POST /api/payments/ingest` → 201 without any header\n- `curl -H \"x-authentik-username: test\" localhost:3001/api/payments` → 200\n\n**SMS Ingest**\n- DSK POS SMS → `source=INGEST`, `currency=EUR`, correct amount/card/recipient\n- Apple Wallet structured body → `type=WALLET`, `source=INGEST`\n- Rate limiter → 429 after 200 req/min\n\n**CSV Upload**\n- Single DSK CSV → rows with `source=UPLOAD`, `currency=BGN`\n- Multiple CSVs in one request → all merged\n- `ТРАНСФЕР СОБСТВЕНИ СМЕТКИ` rows counted in `skipped`, not imported\n- Card regex match from `Основание` column\n- Auto-tags applied (ЗАПЛАТА→Salary, LIDL→Groceries)\n- cp1251 file imports correctly\n\n**UI**\n- Source badge visible in payment table (SMS indigo, CSV emerald)\n- Source dropdown in FilterBar filters correctly\n- Amount shows correct currency per row\n- Upload Panel: drag-and-drop works, result summary shows counts\n- Logout redirects to Authentik sign_out\n- No login form shown (Authentik handles it at NPM level)\n- Tags, send, skip, delete all still work\n\n## Reference Files\n\n- `/volume2/docker/finance/payments-logger/backend/src/routes/payments.js`\n- `/volume2/docker/finance/payments-logger/backend/src/parser.js`\n- `/volume2/docker/finance/payments-logger/backend/src/index.js`\n- `/volume2/docker/finance/payments-logger/backend/src/auth.js`\n- `/volume2/docker/finance/payments-logger/backend/prisma/schema.prisma`\n- `/volume2/docker/finance/payments-logger/frontend/src/App.jsx`\n- `/volume2/docker/finance/payments-logger/frontend/src/components/PaymentTable.jsx`\n- `/volume2/docker/finance/payments-logger/frontend/src/components/FilterBar.jsx`\n- `/volume2/docker/finance/dsk-uploader/dskuploader.py`\n- `/volume2/docker/finance/auth/docker-compose.yml`","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Claude’s Plan","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"ets-create-a-new-generic-sun.md","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"ets-create-a-new-generic-sun.md","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Stayed in plan mode","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":23,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Thinking","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Good question. Here's the full breakdown:","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"Backend Tech Stack — Options","depth":22,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"Backend Tech Stack — Options","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"Option A: Node.js + Express + Prisma (my recommendation)","depth":22,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"Option A: Node.js + Express + Prisma (my recommendation)","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Why:","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"payments-logger is already Node.js/Express/Prisma. The new app is 80% payments-logger with CSV upload added on top. Keeping the same stack means:","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Copy","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"parser.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"verbatim, zero rewrite","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Copy the entire","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"routes/payments.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"with minimal edits","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Same Prisma schema workflow, same migrations, same Docker image","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"The CSV parsing logic (the only Python-specific thing) ports cleanly to","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"csv-parse","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"— it's just regex + string manipulation, nothing pandas-specific","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Trade-off:","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Have to port the Python CSV parsing to JS. It's ~150 lines and mostly string manipulation — straightforward.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"Option B: Python + FastAPI + SQLAlchemy","depth":22,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"Option B: Python + FastAPI + SQLAlchemy","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Rewrite everything in Python. dsk-uploader is Python, so CSV parsing is already done.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Pro:","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Keep the dsk-uploader CSV logic as-is (no porting). Python has better data science libraries if you later add analytics.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Con:","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Lose the entire payments-logger backend (routes, parser, Prisma schema) — full rewrite. FastAPI + SQLAlchemy is a different mental model than Express + Prisma. Frontend stays React anyway, so the stack split doesn't simplify anything.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Verdict:","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"More work overall, gains almost nothing.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"Option C: Hybrid microservices (Node.js backend + Python CSV service)","depth":22,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"Option C: Hybrid microservices (Node.js backend + Python CSV service)","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Keep Node.js as the main API, add a separate Python FastAPI service just for CSV parsing. They share the DB.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Pro:","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Zero porting — Python CSV code used as-is.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Con:","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Two backend services to maintain, deploy, and keep in sync. Inter-service HTTP calls. Two Dockerfiles. For ~150 lines of CSV logic, this is massively over-engineered.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Verdict:","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Not worth it.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"Option D: Python + Flask (exactly like dsk-uploader)","depth":22,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"Option D: Python + Flask (exactly like dsk-uploader)","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Extend dsk-uploader into a full payments app.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Pro:","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Pandas for CSV, no porting.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Con:","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Jinja2 templates instead of React (or add React separately). Would need to reimplement the entire payments-logger (SMS parser, notification system, tag management, pagination/filtering). Flask's Jinja templating is far less capable than the existing React UI. The React frontend is the stronger UI foundation.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Verdict:","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Worst of all options — rebuild the harder parts (UI, SMS parser, notification) for no gain.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"Summary","depth":22,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"Summary","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Option","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CSV porting effort","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"App rewrite effort","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Result quality","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"A (Node.js)","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Medium (150 lines)","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Minimal","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Best","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"B (Python FastAPI)","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"None","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"High (full backend)","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Worse","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"C (Hybrid)","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"None","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Low + infra overhead","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Overkill","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"D (Python Flask)","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"None","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Very high","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Worst","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Option","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"A (Node.js)","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"B (Python FastAPI)","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"C (Hybrid)","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"D (Python Flask)","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CSV porting effort","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Medium (150 lines)","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"None","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"None","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"None","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"App rewrite effort","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Minimal","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"High (full backend)","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Low + infra overhead","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Very high","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Result quality","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Best","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Worse","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Overkill","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Worst","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Option","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CSV porting effort","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"App rewrite effort","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Result quality","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"The CSV parser port (the only cost of Option A) is a one-time ~150 line exercise. Everything else in the plan reuses payments-logger code directly. That's why Node.js is the clear winner here.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Want to adjust the stack, or shall I proceed with Option A?","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Message actions","depth":24,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"ok sounds good. Implement all you suggested","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":23,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Thinking","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Starting implementation. Let me first read all the reference files I'll need to copy from.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"parser.js","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"parser.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"payments.js","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"payments.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":",","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"index.js","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"index.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"App.jsx","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"App.jsx","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"FilterBar.jsx","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"FilterBar.jsx","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"PaymentTable.jsx","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"PaymentTable.jsx","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":23,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Thinking","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Now let me read the remaining frontend files and the Dockerfile from payments-logger.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"main.jsx","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"main.jsx","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"index.css","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"index.css","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"package.json","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"package.json","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Dockerfile","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Dockerfile","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Dockerfile","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Dockerfile","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"vite.config.js","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"vite.config.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"tailwind.config.js","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"tailwind.config.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"postcss.config.js","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"postcss.config.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":23,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Thinking","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"index.html","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"index.html","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"dskuploader.py","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"dskuploader.py","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":23,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Thinking","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Let me also grab the remaining frontend components.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"PaymentCard.jsx","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"PaymentCard.jsx","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"PaymentList.jsx","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"PaymentList.jsx","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"schema.prisma","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"schema.prisma","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":23,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Thinking","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Good, I have everything I need. Let me set up the todo list and start building.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":23,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Thinking","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Update Todos","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Create folder structure and root config files","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write backend Prisma schema and migration","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write backend package.json and Dockerfile","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write backend src files (auth, parser, csvParser, index)","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write backend routes (payments.js, upload.js)","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write frontend config files","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write frontend React components","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Build and verify with docker compose","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Create finance-hub directory structure","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"mkdir -p /volume2/docker/finance/finance-hub/backend/src/routes \\\n /volume2/docker/finance/finance-hub/backend/prisma/migrations/20260508_init \\\n /volume2/docker/finance/finance-hub/frontend/src/components && echo \"done\"","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"done","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"docker-compose.yml","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"docker-compose.yml","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"45 lines","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"version: '3.8'\n\nservices:\n db:\n image: postgres:16-alpine\n restart: unless-stopped\n environment:\n POSTGRES_USER: finance\n POSTGRES_PASSWORD: ${DB_PASSWORD}\n POSTGRES_DB: finance_hub\n volumes:\n - pgdata:/var/lib/postgresql/data\n healthcheck:\n test: [\"CMD-SHELL\", \"pg_isready -U finance -d finance_hub\"]\n interval: 5s\n timeout: 5s\n retries: 5\n\n backend:\n build: ./backend\n restart: unless-stopped\n environment:\n DATABASE_URL: postgresql://finance:${DB_PASSWORD}@db:5432/finance_hub\n PORT: \"3001\"\n NOTIFIER_URL: ${NOTIFIER_URL}\n NOTIFIER_CHANNEL: ${NOTIFIER_CHANNEL:-viber}\n NOTIFY_DEFAULT_PHONE: ${NOTIFY_DEFAULT_PHONE}\n TZ: ${TZ:-Europe/Sofia}\n ports:\n - \"${BACKEND_PORT:-3001}:3001\"\n depends_on:\n db:\n condition: service_healthy\n\n frontend:\n build: ./frontend\n restart: unless-stopped\n ports:\n - \"${FRONTEND_PORT:-5175}:5173\"\n depends_on:\n - backend\n\nvolumes:\n pgdata:","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":".env.example","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":".env.example","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"15 lines","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"# Database\nDB_PASSWORD=change_me_strong_password\n\n# Notifier service (for SMS payment notifications)\nNOTIFIER_URL=https://notifier.lakylak.xyz\nNOTIFIER_CHANNEL=viber\nNOTIFY_DEFAULT_PHONE=+359000000000\n\n# Timezone (used by SMS parser for Bulgarian bank timestamps)\nTZ=Europe/Sofia\n\n# Ports (optional — defaults shown)\nBACKEND_PORT=3001\nFRONTEND_PORT=5175","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":".gitignore","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":".gitignore","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"5 lines","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".env\nnode_modules/\ndist/\n*.log","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Update Todos","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Create folder structure and root config files","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write backend Prisma schema and migration","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write backend package.json and Dockerfile","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write backend src files (auth, parser, csvParser, index)","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write backend routes (payments.js, upload.js)","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write frontend config files","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write frontend React components","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Build and verify with docker compose","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"schema.prisma","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"schema.prisma","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"54 lines","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"generator client {\n provider = \"prisma-client-js\"\n}\n\ndatasource db {\n provider = \"postgresql\"\n url = env(\"DATABASE_URL\")\n}\n\nmodel Payment {\n id Int @id @default(autoincrement())\n rawMessage String @map(\"raw_message\")\n date DateTime?\n type String?\n card String?\n recipient String?\n amount Float?\n currency String? @default(\"EUR\")\n balance Float?\n source Source @default(INGEST)\n status Status @default(UNPROCESSED)\n tags Tag[]\n notifiedAt DateTime? @map(\"notified_at\")\n notifyPhone String? @map(\"notify_phone\")\n debitBgn Float? @map(\"debit_bgn\")\n creditBgn Float? @map(\"credit_bgn\")\n transactionType String? @map(\"transaction_type\")\n payerAccount String? @map(\"payer_account\")\n createdAt DateTime @default(now()) @map(\"created_at\")\n updatedAt DateTime @updatedAt @map(\"updated_at\")\n\n @@map(\"payments\")\n}\n\nmodel Tag {\n id Int @id @default(autoincrement())\n name String @unique\n color String @default(\"#6b7280\")\n payments Payment[]\n\n @@map(\"tags\")\n}\n\nenum Status {\n UNPROCESSED\n SENT\n SKIPPED\n}\n\nenum Source {\n INGEST\n UPLOAD\n}","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"migration.sql","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"migration.sql","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"55 lines","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"-- CreateEnum\nCREATE TYPE \"Status\" AS ENUM ('UNPROCESSED', 'SENT', 'SKIPPED');\nCREATE TYPE \"Source\" AS ENUM ('INGEST', 'UPLOAD');\n\n-- CreateTable\nCREATE TABLE \"payments\" (\n \"id\" SERIAL PRIMARY KEY,\n \"raw_message\" TEXT NOT NULL,\n \"date\" TIMESTAMP(3),\n \"type\" TEXT,\n \"card\" TEXT,\n \"recipient\" TEXT,\n \"amount\" DOUBLE PRECISION,\n \"currency\" TEXT DEFAULT 'EUR',\n \"balance\" DOUBLE PRECISION,\n \"source\" \"Source\" NOT NULL DEFAULT 'INGEST',\n \"status\" \"Status\" NOT NULL DEFAULT 'UNPROCESSED',\n \"notified_at\" TIMESTAMP(3),\n \"notify_phone\" TEXT,\n \"debit_bgn\" DOUBLE PRECISION,\n \"credit_bgn\" DOUBLE PRECISION,\n \"transaction_type\" TEXT,\n \"payer_account\" TEXT,\n \"created_at\" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,\n \"updated_at\" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP\n);\n\n-- CreateTable\nCREATE TABLE \"tags\" (\n \"id\" SERIAL PRIMARY KEY,\n \"name\" TEXT NOT NULL,\n \"color\" TEXT NOT NULL DEFAULT '#6b7280'\n);\n\n-- CreateUniqueIndex\nCREATE UNIQUE INDEX \"tags_name_key\" ON \"tags\"(\"name\");\n\n-- CreateTable (M2M join)\nCREATE TABLE \"_PaymentToTag\" (\n \"A\" INTEGER NOT NULL,\n \"B\" INTEGER NOT NULL,\n CONSTRAINT \"_PaymentToTag_AB_pkey\" PRIMARY KEY (\"A\", \"B\")\n);\n\nCREATE INDEX \"_PaymentToTag_B_index\" ON \"_PaymentToTag\"(\"B\");\n\n-- AddForeignKey\nALTER TABLE \"_PaymentToTag\"\n ADD CONSTRAINT \"_PaymentToTag_A_fkey\"\n FOREIGN KEY (\"A\") REFERENCES \"payments\"(\"id\") ON DELETE CASCADE ON UPDATE CASCADE;\n\nALTER TABLE \"_PaymentToTag\"\n ADD CONSTRAINT \"_PaymentToTag_B_fkey\"\n FOREIGN KEY (\"B\") REFERENCES \"tags\"(\"id\") ON DELETE CASCADE ON UPDATE CASCADE;","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"migration_lock.toml","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"migration_lock.toml","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"4 lines","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"# Please do not edit this file manually\n# It should be added in your version-control system (e.g., Git)\nprovider = \"postgresql\"","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Update Todos","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Create folder structure and root config files","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write backend Prisma schema and migration","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write backend package.json and Dockerfile","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write backend src files (auth, parser, csvParser, index)","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write backend routes (payments.js, upload.js)","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write frontend config files","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write frontend React components","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Build and verify with docker compose","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"package.json","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"package.json","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"26 lines","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"{\n \"name\": \"finance-hub-backend\",\n \"version\": \"1.0.0\",\n \"main\": \"src/index.js\",\n \"scripts\": {\n \"start\": \"node src/index.js\",\n \"dev\": \"nodemon src/index.js\",\n \"prisma:generate\": \"prisma generate\",\n \"prisma:migrate\": \"prisma migrate deploy\"\n },\n \"dependencies\": {\n \"@prisma/client\": \"^5.22.0\",\n \"cors\": \"^2.8.5\",\n \"csv-parse\": \"^5.5.6\",\n \"express\": \"^4.21.1\",\n \"express-rate-limit\": \"^7.4.0\",\n \"iconv-lite\": \"^0.6.3\",\n \"morgan\": \"^1.10.0\",\n \"multer\": \"^1.4.5-lts.1\"\n },\n \"devDependencies\": {\n \"nodemon\": \"^3.1.7\",\n \"prisma\": \"^5.22.0\"\n }\n}","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Dockerfile","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Dockerfile","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"18 lines","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FROM node:20-alpine\n\nRUN apk add --no-cache openssl\n\nWORKDIR /app\n\nCOPY package.json package-lock.json* ./\nRUN npm install\n\nCOPY prisma ./prisma\nRUN npx prisma generate\n\nCOPY src ./src\n\nEXPOSE 3001\n\nCMD [\"sh\", \"-c\", \"npx prisma migrate deploy && node src/index.js\"]","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Update Todos","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Create folder structure and root config files","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write backend Prisma schema and migration","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write backend package.json and Dockerfile","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write backend src files (auth, parser, csvParser, index)","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write backend routes (payments.js, upload.js)","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write frontend config files","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write frontend React components","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Build and verify with docker compose","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"auth.js","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"auth.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"27 lines","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"const PUBLIC_PATHS = new Set([\n '/api/health',\n '/api/payments/ingest',\n]);\n\nfunction authentikMiddleware(req, res, next) {\n if (PUBLIC_PATHS.has(req.path)) return next();\n\n const username = req.headers['x-authentik-username'];\n if (!username) {\n return res.status(401).json({ error: 'Unauthorized — missing Authentik session' });\n }\n\n req.user = {\n username,\n email: req.headers['x-authentik-email'] || null,\n groups: (req.headers['x-authentik-groups'] || '')\n .split(',')\n .map(g => g.trim())\n .filter(Boolean),\n };\n\n next();\n}\n\nmodule.exports = { authentikMiddleware };","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"parser.js","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"parser.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"104 lines","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/**\n * Parses SMS payment messages from Bulgarian banks (DSK Bank, etc.)\n *\n * Supported formats:\n *\n * POS / INTERNET / ECOM / P2P payment:\n * DSK Bank. Na DD/MM/YYYY v HH:MM sa plateni AMOUNT CURRENCY s karta CARD na POS s adres: RECIPIENT. Nalichni: BALANCE CURRENCY.\n *\n * ATM withdrawal:\n * DSK Bank. Na DD/MM/YYYY v HH:MM sa iztegleni AMOUNT CURRENCY s karta CARD ot ATM s adres: RECIPIENT. Nalichni: BALANCE CURRENCY.\n *\n * ATM utility payment (amount may include fee as AMOUNT/FEE):\n * DSK Bank. Na DD/MM/YYYY v HH:MM sa plateni AMOUNT CURRENCY/FEE CURRENCY s karta CARD na ATM s adres:RECIPIENT. Nalichni: BALANCE CURRENCY.\n */\n\nconst LOCAL_TZ = process.env.TZ || 'Europe/Sofia';\n\n/**\n * Convert a local-timezone date/time to a UTC Date object.\n * Uses Intl to resolve the actual UTC offset (DST-aware).\n */\nfunction localToUtc(year, month, day, hour, minute) {\n const naive = new Date(Date.UTC(year, month - 1, day, hour, minute, 0));\n\n const formatter = new Intl.DateTimeFormat('en-US', {\n timeZone: LOCAL_TZ,\n year: 'numeric', month: '2-digit', day: '2-digit',\n hour: '2-digit', minute: '2-digit', second: '2-digit',\n hour12: false,\n });\n\n const parts = {};\n formatter.formatToParts(naive).forEach(p => { parts[p.type] = p.value; });\n\n const localAtNaive = new Date(Date.UTC(\n parseInt(parts.year), parseInt(parts.month) - 1, parseInt(parts.day),\n parseInt(parts.hour) % 24, parseInt(parts.minute), parseInt(parts.second),\n ));\n\n const offsetMs = localAtNaive.getTime() - naive.getTime();\n return new Date(Date.UTC(year, month - 1, day, hour, minute, 0) - offsetMs);\n}\n\nfunction parsePaymentSms(message) {\n const result = {\n rawMessage: message,\n date: null,\n type: null,\n card: null,\n recipient: null,\n amount: null,\n balance: null,\n };\n\n // Date and time: \"Na DD/MM/YYYY v HH:MM\"\n const dateMatch = message.match(/Na (\\d{2})\\/(\\d{2})\\/(\\d{4}) v (\\d{2}):(\\d{2})/i);\n if (dateMatch) {\n const [, day, month, year, hour, minute] = dateMatch;\n result.date = localToUtc(\n parseInt(year), parseInt(month), parseInt(day),\n parseInt(hour), parseInt(minute),\n );\n }\n\n // Card mask: \"s karta 400915***4447\" or \"s karta 483890***7162\"\n const cardMatch = message.match(/s karta\\s+([\\d*]+)/i);\n if (cardMatch) {\n result.card = cardMatch[1];\n }\n\n // Transaction type: supports both prepositions\n // \"na POS\" / \"na ATM\" / \"na INTERNET\" etc. (payment)\n // \"ot ATM\" (withdrawal)\n const typeMatch = message.match(/(?:na|ot)\\s+(POS|ATM|INTERNET|ECOM|P2P)\\b/i);\n if (typeMatch) {\n result.type = typeMatch[1].toUpperCase();\n }\n\n // Recipient address: \"s adres: MERCHANT\" or \"s adres:MERCHANT\" (no space variant)\n const recipientMatch = message.match(/s adres:\\s*([^.]+)\\./i);\n if (recipientMatch) {\n result.recipient = recipientMatch[1].trim();\n }\n\n // Amount: handles both verbs and the AMOUNT/FEE suffix format\n // \"sa plateni 7.78 EUR\"\n // \"sa iztegleni 400.00 EUR\"\n // \"sa plateni 0.50 EUR/0.50 EUR\" → captures 0.50 (the charged amount, ignoring fee)\n const amountMatch = message.match(/sa (?:plateni|iztegleni)\\s+([\\d.,]+)\\s+[A-Z]{3}/i);\n if (amountMatch) {\n result.amount = parseFloat(amountMatch[1].replace(',', '.'));\n }\n\n // Balance: \"Nalichni: 2583.07 EUR.\"\n const balanceMatch = message.match(/Nalichni:\\s*([\\d.,]+)\\s+[A-Z]{3}/i);\n if (balanceMatch) {\n result.balance = parseFloat(balanceMatch[1].replace(',', '.'));\n }\n\n return result;\n}\n\nmodule.exports = { parsePaymentSms };","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"csvParser.js","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"csvParser.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"175 lines","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/**\n * DSK Bank CSV parser — Node.js port of dskuploader.py\n *\n * DSK Bank exports use Windows-1251 (cp1251) encoding.\n * Each row maps to a Payment record with source=UPLOAD, currency=BGN.\n */\n\nconst { parse } = require('csv-parse');\nconst iconv = require('iconv-lite');\n\nconst SKIP_TYPE = 'ТРАНСФЕР СОБСТВЕНИ СМЕТКИ';\nconst CARD_REGEX = /^\\d{6}x{6}\\d{4}$/;\nconst POS_REGEX = /^\\s*ПЛАЩАНЕ\\s+НА\\s+ПОС\\s+\\d{2}\\.\\d{2}\\.\\d{4}\\s+\\d{2}:\\d{2}/;\n\nconst COL = {\n DATE: 'Дата',\n TYPE: 'Вид на трансакцията',\n REASON: 'Основание',\n DEBIT: 'Дебит BGN',\n CREDIT: 'Кредит BGN',\n PAYEE: 'Наредител/Получател',\n ACCT: 'Номер сметка на наредителя / получателя',\n};\n\nconst TAG_RULES = [\n ['reason', 'ЗАПЛАТА', 'Salary'],\n ['reason', 'ТЕГЛЕНЕ НА ATM', 'ATM'],\n ['reason', 'ПЛАЩАНЕ ПО ЗАЕМ', 'Home Credit'],\n ['reason', 'АВТ.ТАКСА ОБСЛУЖВАНЕ', 'Bills'],\n ['transactionType', 'КОМУНАЛНИ УСЛУГИ', 'Bills'],\n ['payee', 'VIVACOM', 'Subscriptions'],\n ['payee', 'Google', 'Subscriptions'],\n ['payee', 'SkyShowtime', 'Subscriptions'],\n ['payee', 'NETFLIX', 'Subscriptions'],\n ['payee', 'LUKOIL', 'Bills'],\n ['payee', 'CityGate', 'Bills'],\n ['payee', 'CBA', 'Groceries'],\n ['payee', 'FANTASTICO', 'Groceries'],\n ['payee', 'LIDL', 'Groceries'],\n];\n\nfunction parseNum(val) {\n if (val == null || val === '') return null;\n if (typeof val === 'number') return isNaN(val) ? null : val;\n const s = String(val).trim().replace(/\\xa0/g, '').replace(/ /g, '').replace(',', '.');\n const n = parseFloat(s);\n return isNaN(n) ? null : n;\n}\n\nfunction parseDate(val) {\n if (!val) return null;\n const s = String(val).trim();\n const m = s.match(/^(\\d{2})\\.(\\d{2})\\.(\\d{4})$/);\n if (m) {\n return new Date(Date.UTC(parseInt(m[3]), parseInt(m[2]) - 1, parseInt(m[1])));\n }\n return null;\n}\n\nfunction processReasonAndCard(reason) {\n if (!reason || typeof reason !== 'string') return { reason: '', card: null };\n\n const parts = reason.trim().split(' ');\n let card = null;\n let cleanReason = reason.trim();\n\n if (parts[0] && CARD_REGEX.test(parts[0])) {\n card = parts[0];\n cleanReason = parts.slice(1).join(' ').trim();\n }\n\n if (POS_REGEX.test(cleanReason)) {\n const posParts = cleanReason.split('<br/>');\n try {\n const dateTime = posParts[0].split('ПОС ')[1];\n cleanReason = `POS PAYMENT ${dateTime}`;\n } catch (_) { /* keep original */ }\n }\n\n return { reason: cleanReason.replace(/\\s+/g, ' ').trim(), card };\n}\n\nfunction generateTags(fields) {\n const tags = new Set();\n for (const [field, keyword, tagName] of TAG_RULES) {\n if ((fields[field] || '').includes(keyword)) {\n tags.add(tagName);\n }\n }\n return Array.from(tags);\n}\n\nfunction processRow(row) {\n const transactionType = (row[COL.TYPE] || '').trim();\n if (transactionType === SKIP_TYPE) return null;\n\n const { reason, card } = processReasonAndCard(row[COL.REASON]);\n const payee = (row[COL.PAYEE] || '').trim();\n const payerAccount = (row[COL.ACCT] || '').trim();\n const debitBgn = parseNum(row[COL.DEBIT]);\n const creditBgn = parseNum(row[COL.CREDIT]);\n const date = parseDate(row[COL.DATE]);\n\n const autoTags = generateTags({ reason, transactionType, payee, debitBgn, creditBgn });\n\n const amount = debitBgn ?? creditBgn ?? null;\n\n const rawMessage = [\n row[COL.DATE] && `Date: ${row[COL.DATE]}`,\n transactionType && `Type: ${transactionType}`,\n payee && `Payee: ${payee}`,\n debitBgn != null && `Debit: ${debitBgn} BGN`,\n creditBgn != null && `Credit: ${creditBgn} BGN`,\n ].filter(Boolean).join(' | ');\n\n return {\n rawMessage,\n date,\n type: null,\n card,\n recipient: payee || null,\n amount,\n currency: 'BGN',\n balance: null,\n source: 'UPLOAD',\n debitBgn,\n creditBgn,\n transactionType: transactionType || null,\n payerAccount: payerAccount || null,\n autoTags,\n };\n}\n\n/**\n * Parse a Buffer containing a DSK Bank CSV (cp1251 or UTF-8).\n * Returns { rows, skipped, errors }.\n */\nasync function parseDskCsv(buffer) {\n // Try cp1251 first (DSK Bank export encoding), fall back to UTF-8\n let text = iconv.decode(buffer, 'cp1251');\n if (!text.includes(COL.DATE)) {\n text = buffer.toString('utf-8');\n }\n\n return new Promise((resolve, reject) => {\n const rows = [];\n const errors = [];\n let skipped = 0;\n\n const parser = parse(text, {\n columns: true,\n skip_empty_lines: true,\n trim: true,\n relax_column_count: true,\n });\n\n parser.on('readable', () => {\n let record;\n while ((record = parser.read()) !== null) {\n try {\n const row = processRow(record);\n if (row === null) { skipped++; } else { rows.push(row); }\n } catch (err) {\n errors.push(err.message);\n }\n }\n });\n\n parser.on('error', reject);\n parser.on('end', () => resolve({ rows, skipped, errors }));\n });\n}\n\nmodule.exports = { parseDskCsv };","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"index.js","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"index.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"39 lines","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"const express = require('express');\nconst cors = require('cors');\nconst morgan = require('morgan');\nconst rateLimit = require('express-rate-limit');\nconst { authentikMiddleware } = require('./auth');\nconst paymentsRouter = require('./routes/payments');\nconst uploadRouter = require('./routes/upload');\n\nconst app = express();\nconst PORT = process.env.PORT || 3001;\n\napp.use(cors());\napp.use(express.json({ limit: '16kb' }));\napp.use(morgan('combined'));\n\n// Rate-limit the public ingest endpoint before auth middleware\nconst ingestLimiter = rateLimit({\n windowMs: 60 * 1000,\n max: 200,\n standardHeaders: true,\n legacyHeaders: false,\n message: { error: 'Too many requests, slow down' },\n});\napp.use('/api/payments/ingest', ingestLimiter);\n\n// Authentik header auth (skips /api/health and /api/payments/ingest)\napp.use(authentikMiddleware);\n\napp.get('/api/health', (_req, res) => {\n res.json({ status: 'ok', timestamp: new Date().toISOString() });\n});\n\napp.use('/api/payments', paymentsRouter);\napp.use('/api/upload', uploadRouter);\n\napp.listen(PORT, '0.0.0.0', () => {\n console.log(`Finance Hub API running on port ${PORT}`);\n});","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Update Todos","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Create folder structure and root config files","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write backend Prisma schema and migration","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write backend package.json and Dockerfile","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write backend src files (auth, parser, csvParser, index)","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write backend routes (payments.js, upload.js)","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write frontend config files","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write frontend React components","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Build and verify with docker compose","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"payments.js","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
597034000661653030
|
6809041652970449887
|
idle
|
accessibility
|
NULL
|
Explorer (⇧⌘E)
Search (⇧⌘F)
Source Control (⌃⇧ Explorer (⇧⌘E)
Search (⇧⌘F)
Source Control (⌃⇧G)
Run and Debug (⇧⌘D)
Remote Explorer
Extensions (⇧⌘X) - 2 require update
2
Claude Code
Containers
EXPLORER
EXPLORER
Explorer Section: finance [SSH: nas]
Explorer Section: finance [SSH: nas]
FINANCE [SSH: NAS]
auth
dsk-uploader
finance-hub
backend
frontend
.env
.env.example
.gitignore
docker-compose.yml
payments-logger
Outline Section
OUTLINE
OUTLINE
Timeline Section
TIMELINE
TIMELINE
docker-compose.yml, Editor Group 1
.env, Editor Group 1
version: '3.8'
services:
db:
image: postgres:16-alpine
restart: unless-stopped
environment:
POSTGRES_USER: finance
POSTGRES_PASSWORD: [PASSWORD]
POSTGRES_DB: finance_hub
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U finance -d finance_hub"]
interval: 5s
timeout: 5s
retries: 5
backend:
build: ./backend
restart: unless-stopped
environment:
DATABASE_URL: [CONNECTION_STRING]
PORT: "3001"
NOTIFIER_URL: ${NOTIFIER_URL}
NOTIFIER_CHANNEL: ${NOTIFIER_CHANNEL:-viber}
NOTIFY_DEFAULT_PHONE: ${NOTIFY_DEFAULT_PHONE}
TZ: ${TZ:-Europe/Sofia}
ports:
- "${BACKEND_PORT:-3001}:3001"
depends_on:
db:
condition: service_healthy
frontend:
build: ./frontend
restart: unless-stopped
ports:
- "${FRONTEND_PORT:-5175}:5173"
depends_on:
- backend
volumes:
pgdata:
version: '3.8'
services:
db:
image: postgres:16-alpine
restart: unless-stopped
environment:
POSTGRES_USER: finance
POSTGRES_PASSWORD: [PASSWORD]
POSTGRES_DB: finance_hub
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U finance -d finance_hub"]
interval: 5s
timeout: 5s
retries: 5
backend:
build: ./backend
restart: unless-stopped
environment:
DATABASE_URL: [CONNECTION_STRING]
PORT: "3001"
NOTIFIER_URL: ${NOTIFIER_URL}
NOTIFIER_CHANNEL: ${NOTIFIER_CHANNEL:-viber}
NOTIFY_DEFAULT_PHONE: ${NOTIFY_DEFAULT_PHONE}
TZ: ${TZ:-Europe/Sofia}
ports:
- "${BACKEND_PORT:-3001}:3001"
depends_on:
db:
condition: service_healthy
frontend:
build: ./frontend
restart: unless-stopped
ports:
- "${FRONTEND_PORT:-5175}:5173"
depends_on:
- backend
volumes:
pgdata:
Design new payment-logge…, Editor Group 2
remote SSH: nas
SSH: nas
No Problems
0
0
No Ports Forwarded
0
Notifications
Sign In
Sign In
Info: Setting up SSH Host nas: Setting up SSH tunnel
Design new payment-logger and dsk-uploader hybrid app
Session history
New session
Message actions
payments.js
payments.js
ets create a new app that should be combination of payment-logger and dsk-uploader. It should have authorization via authentik (auth folder). All three folders (payment-logger, dsk-uploader and auth) are just refference these will be removed later. Auth project is separated it lives on its own. First reveiw them and see how these should be combined. It will be whole new app (also the folder name). Think very carefully of whatr these two apps do and how cold they be combined. THerer should be common db and uploader should store data the same way the /ingest does. It should be properly marked in UI if it is upload or ingest or both. FIrst think of tech stack and plan carefully.
Thinking
Thinking
I'll explore all three reference projects in parallel to understand their structure before planning.
Agent:
Explore payment-logger app structure and functionality
IN
Explore the /volume2/docker/finance/payments-logger directory thoroughly. I need to understand:
1. Tech stack (frontend framework, backend framework, database)
2. What the app does - its core purpose and features
3. Database schema - all tables, relationships
4. API routes - all endpoints, their purpose and request/response shapes
5. How data flows (ingest, storage, retrieval)
6. Any auth/middleware setup
7. Docker/deployment setup
8. Key files and their roles
Report with: directory structure, tech stack summary, database schema details, all API endpoints listed, UI features, and how data is ingested. Be thorough on the /ingest endpoint specifically.
Agent:
Explore dsk-uploader app structure and functionality
IN
Explore the /volume2/docker/finance/dsk-uploader directory thoroughly. I need to understand:
1. Tech stack (frontend framework, backend framework, database)
2. What the app does - its core purpose and features
3. Database schema - all tables, relationships
4. API routes - all endpoints, their purpose and request/response shapes
5. How file uploads work - what files, what format, how parsed
6. Any auth/middleware setup
7. Docker/deployment setup
8. Key files and their roles
Report with: directory structure, tech stack summary, database schema details, all API endpoints listed, UI features, how file upload parsing works, and what data is extracted from uploads. Be very thorough about the data model and what fields are stored.
Agent:
Explore auth folder and authentik integration
IN
Explore the /volume2/docker/finance/auth directory thoroughly. I need to understand:
1. What auth system is being used (Authentik)
2. How authentication/authorization is implemented - OAuth2, OIDC, session tokens, JWT?
3. Middleware - how is auth enforced on routes?
4. Any frontend auth flow - login redirect, token handling, protected routes
5. Environment variables related to auth
6. Docker/deployment setup for the auth service itself
7. Any example of how other apps integrate with this auth
Report with: directory structure, auth flow description, middleware code, environment variable names, and integration patterns. This is a reference for building auth into a new combined app.
Message actions
payments.js
payments.js
continue
Thinking
Thinking
Launching parallel exploration of all three reference projects.
Agent:
Explore payment-logger app structure
IN
Explore the /volume2/docker/finance/payments-logger directory thoroughly. I need to understand:
1. Full directory structure (tree)
2. Tech stack (frontend framework, backend framework, database, etc.)
3. What the app does - its core functionality
4. How data is ingested (look at /ingest route especially)
5. Database schema (what tables/collections exist)
6. API routes and their purposes
7. Frontend pages and components
8. Docker setup
9. Any auth/session handling
Please read key files: package.json files, main entry points, route files, database schema files, docker-compose.yml, and any frontend components. Be thorough - I need a complete picture to plan a new combined app.
Agent:
Explore dsk-uploader app structure
IN
Explore the /volume2/docker/finance/dsk-uploader directory thoroughly. I need to understand:
1. Full directory structure (tree)
2. Tech stack (frontend framework, backend framework, database, etc.)
3. What the app does - its core functionality
4. How file uploads work (what format, what processing happens)
5. Database schema (what tables/collections exist)
6. API routes and their purposes
7. Frontend pages and components
8. Docker setup
9. Any auth/session handling
Please read key files: package.json files, main entry points, route files, database schema files, docker-compose.yml, and any frontend components. Be thorough - I need a complete picture to plan a new combined app.
Agent:
Explore auth project structure
IN
Explore the /volume2/docker/finance/auth directory thoroughly. I need to understand:
1. Full directory structure (tree)
2. What authentication system is used (authentik integration details)
3. How OAuth/OIDC flow works
4. Any middleware or helper functions for protecting routes
5. Session management approach
6. How frontend handles auth state
7. Any example of how other apps integrate with this auth system
8. Docker setup and environment variables
Please read all files carefully - this auth system will be integrated into a new combined app. I need to understand exactly how to use it.
Thinking
Thinking
Now I have a complete picture of all three. Let me design the plan.
Agent:
Design combined app architecture
IN
Design a detailed implementation plan for a new combined web app that merges two existing applications. Here is full context:
---
## App 1: payments-logger (Node.js)
- **Purpose**: Ingest Bulgarian bank SMS → parse → store in PostgreSQL → review/tag/notify in React UI
- **Stack**: Node.js 20 + Express + Prisma 5 + PostgreSQL 16 + React 18 + Vite + Tailwind CSS
- **Auth**: Custom JWT (bcryptjs + jose), tokens in localStorage
- **Ingest**: POST /api/payments/ingest (public) — SMS text OR structured JSON (Apple Wallet)
- **Schema** (PostgreSQL via Prisma):
- `payments` table: id, raw_message, date, type (POS/ATM/INTERNET/ECOM/P2P/WALLET), card, recipient, amount, balance, status (UNPROCESSED/SENT/SKIPPED), notifyPhone, notifiedAt, created_at, updated_at
- `tags` table: id, name, color — M2M with payments via `_PaymentToTag`
- `users` table: id, username, hashed_password (this will be REMOVED)
- **UI**: Single-page React app — PaymentTable (sortable, filterable, taggable), FilterBar, status actions (send/skip), notification system
- **Parser** (backend/src/parser.js): Regex parser for Bulgarian DSK Bank SMS, extracts date/time (DD/MM/YYYY HH:MM), card mask, transaction type, recipient, amount, balance
## App 2: dsk-uploader (Python/Flask)
- **Purpose**: Upload DSK bank CSV exports → parse/normalize → upload to Notion database
- **Stack**: Python 3.11 + Flask + Pandas + Custom Notion SDK + Bootstrap 5
- **Auth**: None (open)
- **CSV format** (DSK Bank Bulgarian format, columns):
- `Дата` (date, DD.MM.YYYY)
- `Вид на трансакцията` (transaction type, Bulgarian)
- `Основание` (reason/description — contains card number regex: `^\d{6}x{6}\d{4}$`)
- `Дебит BGN` (debit amount, may be empty)
- `Кредит BGN` (credit amount, may be empty)
- `Наредител/Получател` (orderer/recipient name)
- `Номер сметка на наредителя / получателя` (account number)
- **Processing**: merge multiple CSVs, normalize dates, extract card numbers from reason via regex, auto-generate tags (keyword heuristics: ЗАПЛАТА→Salary, NETFLIX→Subscriptions, etc.), filter internal transfers
- **Output**: Notion database pages (this will be REPLACED with local PostgreSQL)
## App 3: auth (Authentik)
- **Mode**: Proxy mode via NPM (forward auth)
- **How it works**: NPM intercepts all requests, calls Authentik outpost's auth endpoint. On success, NPM injects headers into proxied request:
- `X-authentik-username`
- `X-authentik-email`
- `X-authentik-groups`
- **No code integration needed** in the app itself — just trust these headers from NPM
- **Logout**: Redirect user to `/outpost.goauthentik.io/sign_out`
---
## What the New Combined App Must Do
1. **Single PostgreSQL database** for all transactions
2. **SMS Ingest** (public endpoint) — same as payments-logger /ingest, source=INGEST
3. **CSV Upload** (authenticated) — parse DSK CSV files, store transactions with source=UPLOAD into the same DB schema
4. **Unified UI** — show all payments in one table regardless of source
5. **Source indicator** in UI — badge showing "INGEST", "UPLOAD", or "BOTH" (if duplicate detection added)
6. **Source filter** in FilterBar — filter by All/Ingest/Upload
7. **Authentik auth** — remove custom JWT entirely; trust X-authentik-* headers from NPM
8. **All existing payments-logger features**: tagging, send notification, skip, status tracking, filters, sorting, pagination
9. **Remove Notion dependency entirely** — all data stays in local PostgreSQL
---
## Technical Constraints
- Keep Node.js backend (not Python) — extend payments-logger's stack
- CSV parsing: use `csv-parse` npm package (handles encoding, streaming)
- File upload: use `multer` npm middleware
- Auth middleware: read X-authentik-username header, 401 if missing (but /api/payments/ingest stays public)
- Add `source` enum field (INGEST/UPLOAD) to payments schema
- Add `currency` field (EUR for SMS ingest, BGN for CSV uploads) — or just store as-is
- Remove `users` table from schema
---
## Please Design
1. Complete folder structure for the new app (suggest name: "finance-hub" or similar — note this is a placeholder, user will confirm)
2. Prisma schema with new fields (`source`, `currency`)
3. All backend API routes
4. CSV parser design in Node.js (port of the Python logic)
5. Authentik auth middleware
6. Frontend component structure (React) — what's reused from payments-logger, what's new
7. Docker Compose setup
8. Environment variables needed
9. Step-by-step implementation order
10. Verification checklist
Be specific about file paths and code structure. This will be used to write actual implementation code.
Thinking
Thinking
Good plan. Let me ask the one thing I need before writing the final plan.
AskUserQuestion
OUT
User has answered your questions: "What should the new combined app be called? This will be the folder name under /volume2/docker/finance/ and the app branding."="finance-hub". You can now continue with the user's answers in mind.
Thinking
Thinking
Writing the final plan now.
Thinking
Thinking
Write
ets-create-a-new-generic-sun.md
ets-create-a-new-generic-sun.md
326 lines
# finance-hub — Implementation Plan
## Context
Two separate finance apps exist as references and will be retired:
- **payments-logger** (Node.js/React): Ingests Bulgarian bank SMS notifications, stores payments in PostgreSQL, provides a review/tag/notify UI.
- **dsk-uploader** (Python/Flask): Uploads DSK bank CSV exports, parses them, sends to Notion.
The new app **finance-hub** (`/volume2/docker/finance/finance-hub/`) replaces both with a single unified system: all transactions (SMS-ingested and CSV-uploaded) land in one PostgreSQL database and one React UI. Authentication is delegated entirely to Authentik (proxy mode via NPM — no custom JWT).
---
## Tech Stack
| Layer | Choice | Rationale |
|-------|--------|-----------|
| Backend | Node.js 20 + Express + Prisma 5 | Extends payments-logger; no Python needed |
| CSV parsing | `csv-parse` + `iconv-lite` | Handles Bulgarian cp1251 encoding, RFC4180 quoted fields |
| File upload | `multer` (memory storage) | Bank CSVs are small (<500 KB), no disk cleanup needed |
| Database | PostgreSQL 16 | Same as payments-logger |
| Frontend | React 18 + Vite + Tailwind CSS + Lucide React | Same as payments-logger |
| Auth | Authentik proxy via NPM headers | No custom JWT; removes users table entirely |
| Container | Docker Compose | Same pattern as both reference apps |
**Removed vs payments-logger:** `bcryptjs`, `jose`, `users` table, login form, JWT storage.
**Removed vs dsk-uploader:** Python/Flask, Pandas, Notion SDK, all Notion references.
**Added:** `csv-parse`, `iconv-lite`, `multer`, `source` + `currency` fields, `UploadPanel` component.
---
## Folder Structure
```
/volume2/docker/finance/finance-hub/
├── docker-compose.yml
├── .env
├── .env.example
├── .gitignore
├── backend/
│ ├── Dockerfile
│ ├── package.json
│ ├── prisma/
│ │ ├── schema.prisma
│ │ └── migrations/
│ │ ├── migration_lock.toml
│ │ └── 20260508_init/
│ │ └── migration.sql
│ └── src/
│ ├── index.js ← entry point (Authentik middleware wired here)
│ ├── auth.js ← Authentik header middleware (replaces JWT auth)
│ ├── parser.js ← SMS parser (copy verbatim from payments-logger)
│ ├── csvParser.js ← NEW: DSK CSV parser (port of Python dskuploader.py)
│ └── routes/
│ ├── payments.js ← existing routes + source/currency additions
│ └── upload.js ← NEW: POST /api/upload/csv
└── frontend/
├── Dockerfile
├── package.json
├── vite.config.js
├── tailwind.config.js
├── postcss.config.js
├── index.html
└── src/
├── main.jsx ← remove AuthProvider wrapper
├── index.css
├── App.jsx ← remove auth state, add Upload tab toggle
└── components/
├── FilterBar.jsx ← add source filter select
├── PaymentTable.jsx ← add Source badge column + currency display
├── PaymentCard.jsx ← minor source badge addition
├── PaymentList.jsx ← unchanged
└── UploadPanel.jsx ← NEW: drag-and-drop CSV upload UI
```
---
## Database Schema (Prisma)
File: `backend/prisma/schema.prisma`
```prisma
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model Payment {
id Int @id @default(autoincrement())
rawMessage String @map("raw_message")
date DateTime?
type String?
card String?
recipient String?
amount Float?
currency String? @default("EUR")
balance Float?
source Source @default(INGEST)
status Status @default(UNPROCESSED)
tags Tag[]
notifiedAt DateTime? @map("notified_at")
notifyPhone String? @map("notify_phone")
debitBgn Float? @map("debit_bgn")
creditBgn Float? @map("credit_bgn")
transactionType String? @map("transaction_type")
payerAccount String? @map("payer_account")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@map("payments")
}
model Tag {
id Int @id @default(autoincrement())
name String @unique
color String @default("#6b7280")
payments Payment[]
@@map("tags")
}
enum Status { UNPROCESSED SENT SKIPPED }
enum Source { INGEST UPLOAD }
```
**Key decisions:**
- No `User` model — Authentik owns identity.
- `currency`: `EUR` for SMS ingest, `BGN` for CSV uploads.
- `debitBgn`, `creditBgn`, `transactionType`, `payerAccount`: nullable CSV-only columns; INGEST rows store nulls. Avoids a union query for the unified list view.
- `balance` is always null for CSV rows (DSK export does not include running balance).
- Fresh consolidated migration — no data migration from reference apps required.
---
## API Routes
| Method | Path | Auth | Description |
|--------|------|------|-------------|
| GET | /api/health | public | Health check |
| POST | /api/payments/ingest | public | SMS or structured ingest (source=INGEST) |
| GET | /api/payments | required | List with filters/sort/pagination (+ source filter) |
| GET | /api/payments/meta/tags | required | All tags |
| GET | /api/payments/meta/filters | required | Filter options incl. `sources` array |
| GET | /api/payments/:id | required | Single payment |
| PATCH | /api/payments/:id | required | Update status |
| DELETE | /api/payments/:id | required | Delete |
| POST | /api/payments/:id/send | required | Send notification |
| POST | /api/payments/:id/skip | required | Skip |
| POST | /api/payments/:id/tags | required | Add/upsert tag |
| DELETE | /api/payments/:id/tags/:tagId | required | Remove tag |
| POST | /api/upload/csv | required | DSK CSV file upload (source=UPLOAD) |
---
## Key Implementation Details
### auth.js (replaces entire old auth module)
```js
const PUBLIC_PATHS = new Set(['/api/health', '/api/payments/ingest']);
function authentikMiddleware(req, res, next) {
if (PUBLIC_PATHS.has(req.path)) return next();
const username = req.headers['x-authentik-username'];
if (!username) return res.status(401).json({ error: 'Unauthorized' });
req.user = {
username,
email: req.headers['x-authentik-email'] || null,
groups: (req.headers['x-authentik-groups'] || '').split(',').map(g => g.trim()).filter(Boolean),
};
next();
}
module.exports = { authentikMiddleware };
```
### csvParser.js (port of dskuploader.py)
- `iconv-lite` decodes buffer as cp1251 (DSK Bank export encoding), falls back to UTF-8
- `csv-parse` parses the decoded text with `columns: true`
- Columns: `Дата`, `Вид на трансакцията`, `Основание`, `Дебит BGN`, `Кредит BGN`, `Наредител/Получател`, `Номер сметка на наредителя / получателя`
- Card extraction: regex `/^\d{6}x{6}\d{4}$/` on first token of `Основание`
- Skips rows where `Вид на трансакцията === 'ТРАНСФЕР СОБСТВЕНИ СМЕТКИ'`
- Auto-tags via keyword rules (ЗАПЛАТА→Salary, LIDL→Groceries, NETFLIX→Subscriptions, etc.) — same logic as Python `generate_tags()`
- Returns `{ rows: PaymentData[], skipped: number, errors: string[] }`
### payments.js changes from payments-logger
1. Add `source: 'INGEST'` and `currency` to the `/ingest` create call
2. Add `source` to the `GET /` where clause filter
3. Add `sources` to `meta/filters` response
4. Currency-aware amount formatting in notification message
5. Remove all JWT/auth references (no `/auth/register`, `/auth/login`)
### upload.js (new)
- `multer` memory storage, max 10 files × 10 MB
- Calls `parseDskCsv(buffer)` per file
- Upserts tags via `prisma.tag.upsert` then connects
- Returns `{ imported, skipped, errors, payments[] }`
### Frontend changes
- **Delete**: `auth.js`, `AuthProvider.jsx`
- **main.jsx**: Remove `<AuthProvider>` wrapper
- **App.jsx**: Replace `authFetch` with plain `fetch` (Authentik session cookie travels automatically); logout → `window.location.href = '/outpost.goauthentik.io/sign_out'`; add "Payments" / "Upload CSV" tab toggle
- **FilterBar.jsx**: Add source `<select>` (All / SMS Ingest / CSV Upload); widen grid to 5 cols
- **PaymentTable.jsx**: Add `Source` column with `SMS` (indigo) / `CSV` (emerald) badge; show `${amount} ${currency}` in amount cell
- **UploadPanel.jsx** (new): Drag-and-drop zone + file list + import button + result summary with error accordion; calls `POST /api/upload/csv` with `FormData`
---
## Docker Compose
```yaml
services:
db:
image: postgres:16-alpine
environment: { POSTGRES_USER: finance, POSTGRES_PASSWORD: [PASSWORD] POSTGRES_DB: finance_hub }
volumes: [pgdata:/var/lib/postgresql/data]
healthcheck: { test: pg_isready -U finance -d finance_hub, interval: 5s }
backend:
build: ./backend
environment:
DATABASE_URL: [CONNECTION_STRING]
PORT: "3001"
NOTIFIER_URL: ${NOTIFIER_URL}
NOTIFIER_CHANNEL: ${NOTIFIER_CHANNEL:-viber}
NOTIFY_DEFAULT_PHONE: ${NOTIFY_DEFAULT_PHONE}
TZ: ${TZ:-Europe/Sofia}
ports: ["${BACKEND_PORT:-3001}:3001"]
depends_on: { db: { condition: service_healthy } }
frontend:
build: ./frontend
ports: ["${FRONTEND_PORT:-5175}:5173"]
depends_on: [backend]
volumes: { pgdata: }
```
**NPM setup:** Frontend port proxied through Authentik forward auth. Backend port exposed separately (unprotected) so the public `/api/payments/ingest` remains reachable by iOS Shortcuts / SMS gateways without login.
---
## Environment Variables (.env)
```bash
[ENV_SECRET]
NOTIFIER_URL=[URL_WITH_CREDENTIALS] @default(autoincrement())
rawMessage String @map("raw_message")
date DateTime?
type String?
card String?
recipient String?
amount Float?
currency String? @default("EUR")
balance Float?
source Source @default(INGEST)
status Status @default(UNPROCESSED)
tags Tag[]
notifiedAt DateTime? @map("notified_at")
notifyPhone String? @map("notify_phone")
debitBgn Float? @map("debit_bgn")
creditBgn Float? @map("credit_bgn")
transactionType String? @map("transaction_type")
payerAccount String? @map("payer_account")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@map("payments")
}
model Tag {
id Int @id @default(autoincrement())
name String @unique
color String @default("#6b7280")
payments Payment[]
@@map("tags")
}
enum Status {
UNPROCESSED
SENT
SKIPPED
}
enum Source {
INGEST
UPLOAD
}
Write
migration.sql
migration.sql
55 lines
-- CreateEnum
CREATE TYPE "Status" AS ENUM ('UNPROCESSED', 'SENT', 'SKIPPED');
CREATE TYPE "Source" AS ENUM ('INGEST', 'UPLOAD');
-- CreateTable
CREATE TABLE "payments" (
"id" SERIAL PRIMARY KEY,
"raw_message" TEXT NOT NULL,
"date" TIMESTAMP(3),
"type" TEXT,
"card" TEXT,
"recipient" TEXT,
"amount" DOUBLE PRECISION,
"currency" TEXT DEFAULT 'EUR',
"balance" DOUBLE PRECISION,
"source" "Source" NOT NULL DEFAULT 'INGEST',
"status" "Status" NOT NULL DEFAULT 'UNPROCESSED',
"notified_at" TIMESTAMP(3),
"notify_phone" TEXT,
"debit_bgn" DOUBLE PRECISION,
"credit_bgn" DOUBLE PRECISION,
"transaction_type" TEXT,
"payer_account" TEXT,
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP
);
-- CreateTable
CREATE TABLE "tags" (
"id" SERIAL PRIMARY KEY,
"name" TEXT NOT NULL,
"color" TEXT NOT NULL DEFAULT '#6b7280'
);
-- CreateUniqueIndex
CREATE UNIQUE INDEX "tags_name_key" ON "tags"("name");
-- CreateTable (M2M join)
CREATE TABLE "_PaymentToTag" (
"A" INTEGER NOT NULL,
"B" INTEGER NOT NULL,
CONSTRAINT "_PaymentToTag_AB_pkey" PRIMARY KEY ("A", "B")
);
CREATE INDEX "_PaymentToTag_B_index" ON "_PaymentToTag"("B");
-- AddForeignKey
ALTER TABLE "_PaymentToTag"
ADD CONSTRAINT "_PaymentToTag_A_fkey"
FOREIGN KEY ("A") REFERENCES "payments"("id") ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE "_PaymentToTag"
ADD CONSTRAINT "_PaymentToTag_B_fkey"
FOREIGN KEY ("B") REFERENCES "tags"("id") ON DELETE CASCADE ON UPDATE CASCADE;
Write
migration_lock.toml
migration_lock.toml
4 lines
# Please do not edit this file manually
# It should be added in your version-control system (e.g., Git)
provider = "postgresql"
Update Todos
Create folder structure and root config files
Write backend Prisma schema and migration
Write backend package.json and Dockerfile
Write backend src files (auth, parser, csvParser, index)
Write backend routes (payments.js, upload.js)
Write frontend config files
Write frontend React components
Build and verify with docker compose
Write
package.json
package.json
26 lines
{
"name": "finance-hub-backend",
"version": "1.0.0",
"main": "src/index.js",
"scripts": {
"start": "node src/index.js",
"dev": "nodemon src/index.js",
"prisma:generate": "prisma generate",
"prisma:migrate": "prisma migrate deploy"
},
"dependencies": {
"@prisma/client": "^5.22.0",
"cors": "^2.8.5",
"csv-parse": "^5.5.6",
"express": "^4.21.1",
"express-rate-limit": "^7.4.0",
"iconv-lite": "^0.6.3",
"morgan": "^1.10.0",
"multer": "^1.4.5-lts.1"
},
"devDependencies": {
"nodemon": "^3.1.7",
"prisma": "^5.22.0"
}
}
Write
Dockerfile
Dockerfile
18 lines
FROM node:20-alpine
RUN apk add --no-cache openssl
WORKDIR /app
COPY package.json package-lock.json* ./
RUN npm install
COPY prisma ./prisma
RUN npx prisma generate
COPY src ./src
EXPOSE 3001
CMD ["sh", "-c", "npx prisma migrate deploy && node src/index.js"]
Update Todos
Create folder structure and root config files
Write backend Prisma schema and migration
Write backend package.json and Dockerfile
Write backend src files (auth, parser, csvParser, index)
Write backend routes (payments.js, upload.js)
Write frontend config files
Write frontend React components
Build and verify with docker compose
Write
auth.js
auth.js
27 lines
const PUBLIC_PATHS = new Set([
'/api/health',
'/api/payments/ingest',
]);
function authentikMiddleware(req, res, next) {
if (PUBLIC_PATHS.has(req.path)) return next();
const username = req.headers['x-authentik-username'];
if (!username) {
return res.status(401).json({ error: 'Unauthorized — missing Authentik session' });
}
req.user = {
username,
email: req.headers['x-authentik-email'] || null,
groups: (req.headers['x-authentik-groups'] || '')
.split(',')
.map(g => g.trim())
.filter(Boolean),
};
next();
}
module.exports = { authentikMiddleware };
Write
parser.js
parser.js
104 lines
/**
* Parses SMS payment messages from Bulgarian banks (DSK Bank, etc.)
*
* Supported formats:
*
* POS / INTERNET / ECOM / P2P payment:
* DSK Bank. Na DD/MM/YYYY v HH:MM sa plateni AMOUNT CURRENCY s karta CARD na POS s adres: RECIPIENT. Nalichni: BALANCE CURRENCY.
*
* ATM withdrawal:
* DSK Bank. Na DD/MM/YYYY v HH:MM sa iztegleni AMOUNT CURRENCY s karta CARD ot ATM s adres: RECIPIENT. Nalichni: BALANCE CURRENCY.
*
* ATM utility payment (amount may include fee as AMOUNT/FEE):
* DSK Bank. Na DD/MM/YYYY v HH:MM sa plateni AMOUNT CURRENCY/FEE CURRENCY s karta CARD na ATM s adres:RECIPIENT. Nalichni: BALANCE CURRENCY.
*/
const LOCAL_TZ = process.env.TZ || 'Europe/Sofia';
/**
* Convert a local-timezone date/time to a UTC Date object.
* Uses Intl to resolve the actual UTC offset (DST-aware).
*/
function localToUtc(year, month, day, hour, minute) {
const naive = new Date(Date.UTC(year, month - 1, day, hour, minute, 0));
const formatter = new Intl.DateTimeFormat('en-US', {
timeZone: LOCAL_TZ,
year: 'numeric', month: '2-digit', day: '2-digit',
hour: '2-digit', minute: '2-digit', second: '2-digit',
hour12: false,
});
const parts = {};
formatter.formatToParts(naive).forEach(p => { parts[p.type] = p.value; });
const localAtNaive = new Date(Date.UTC(
parseInt(parts.year), parseInt(parts.month) - 1, parseInt(parts.day),
parseInt(parts.hour) % 24, parseInt(parts.minute), parseInt(parts.second),
));
const offsetMs = localAtNaive.getTime() - naive.getTime();
return new Date(Date.UTC(year, month - 1, day, hour, minute, 0) - offsetMs);
}
function parsePaymentSms(message) {
const result = {
rawMessage: message,
date: null,
type: null,
card: null,
recipient: null,
amount: null,
balance: null,
};
// Date and time: "Na DD/MM/YYYY v HH:MM"
const dateMatch = message.match(/Na (\d{2})\/(\d{2})\/(\d{4}) v (\d{2}):(\d{2})/i);
if (dateMatch) {
const [, day, month, year, hour, minute] = dateMatch;
result.date = localToUtc(
parseInt(year), parseInt(month), parseInt(day),
parseInt(hour), parseInt(minute),
);
}
// Card mask: "s karta 400915***4447" or "s karta 483890***7162"
const cardMatch = message.match(/s karta\s+([\d*]+)/i);
if (cardMatch) {
result.card = cardMatch[1];
}
// Transaction type: supports both prepositions
// "na POS" / "na ATM" / "na INTERNET" etc. (payment)
// "ot ATM" (withdrawal)
const typeMatch = message.match(/(?:na|ot)\s+(POS|ATM|INTERNET|ECOM|P2P)\b/i);
if (typeMatch) {
result.type = typeMatch[1].toUpperCase();
}
// Recipient address: "s adres: MERCHANT" or "s adres:MERCHANT" (no space variant)
const recipientMatch = message.match(/s adres:\s*([^.]+)\./i);
if (recipientMatch) {
result.recipient = recipientMatch[1].trim();
}
// Amount: handles both verbs and the AMOUNT/FEE suffix format
// "sa plateni 7.78 EUR"
// "sa iztegleni 400.00 EUR"
// "sa plateni 0.50 EUR/0.50 EUR" → captures 0.50 (the charged amount, ignoring fee)
const amountMatch = message.match(/sa (?:plateni|iztegleni)\s+([\d.,]+)\s+[A-Z]{3}/i);
if (amountMatch) {
result.amount = parseFloat(amountMatch[1].replace(',', '.'));
}
// Balance: "Nalichni: 2583.07 EUR."
const balanceMatch = message.match(/Nalichni:\s*([\d.,]+)\s+[A-Z]{3}/i);
if (balanceMatch) {
result.balance = parseFloat(balanceMatch[1].replace(',', '.'));
}
return result;
}
module.exports = { parsePaymentSms };
Write
csvParser.js
csvParser.js
175 lines
/**
* DSK Bank CSV parser — Node.js port of dskuploader.py
*
* DSK Bank exports use Windows-1251 (cp1251) encoding.
* Each row maps to a Payment record with source=UPLOAD, currency=BGN.
*/
const { parse } = require('csv-parse');
const iconv = require('iconv-lite');
const SKIP_TYPE = 'ТРАНСФЕР СОБСТВЕНИ СМЕТКИ';
const CARD_REGEX = /^\d{6}x{6}\d{4}$/;
const POS_REGEX = /^\s*ПЛАЩАНЕ\s+НА\s+ПОС\s+\d{2}\.\d{2}\.\d{4}\s+\d{2}:\d{2}/;
const COL = {
DATE: 'Дата',
TYPE: 'Вид на трансакцията',
REASON: 'Основание',
DEBIT: 'Дебит BGN',
CREDIT: 'Кредит BGN',
PAYEE: 'Наредител/Получател',
ACCT: 'Номер сметка на наредителя / получателя',
};
const TAG_RULES = [
['reason', 'ЗАПЛАТА', 'Salary'],
['reason', 'ТЕГЛЕНЕ НА ATM', 'ATM'],
['reason', 'ПЛАЩАНЕ ПО ЗАЕМ', 'Home Credit'],
['reason', 'АВТ.ТАКСА ОБСЛУЖВАНЕ', 'Bills'],
['transactionType', 'КОМУНАЛНИ УСЛУГИ', 'Bills'],
['payee', 'VIVACOM', 'Subscriptions'],
['payee', 'Google', 'Subscriptions'],
['payee', 'SkyShowtime', 'Subscriptions'],
['payee', 'NETFLIX', 'Subscriptions'],
['payee', 'LUKOIL', 'Bills'],
['payee', 'CityGate', 'Bills'],
['payee', 'CBA', 'Groceries'],
['payee', 'FANTASTICO', 'Groceries'],
['payee', 'LIDL', 'Groceries'],
];
function parseNum(val) {
if (val == null || val === '') return null;
if (typeof val === 'number') return isNaN(val) ? null : val;
const s = String(val).trim().replace(/\xa0/g, '').replace(/ /g, '').replace(',', '.');
const n = parseFloat(s);
return isNaN(n) ? null : n;
}
function parseDate(val) {
if (!val) return null;
const s = String(val).trim();
const m = s.match(/^(\d{2})\.(\d{2})\.(\d{4})$/);
if (m) {
return new Date(Date.UTC(parseInt(m[3]), parseInt(m[2]) - 1, parseInt(m[1])));
}
return null;
}
function processReasonAndCard(reason) {
if (!reason || typeof reason !== 'string') return { reason: '', card: null };
const parts = reason.trim().split(' ');
let card = null;
let cleanReason = reason.trim();
if (parts[0] && CARD_REGEX.test(parts[0])) {
card = parts[0];
cleanReason = parts.slice(1).join(' ').trim();
}
if (POS_REGEX.test(cleanReason)) {
const posParts = cleanReason.split('<br/>');
try {
const dateTime = posParts[0].split('ПОС ')[1];
cleanReason = `POS PAYMENT ${dateTime}`;
} catch (_) { /* keep original */ }
}
return { reason: cleanReason.replace(/\s+/g, ' ').trim(), card };
}
function generateTags(fields) {
const tags = new Set();
for (const [field, keyword, tagName] of TAG_RULES) {
if ((fields[field] || '').includes(keyword)) {
tags.add(tagName);
}
}
return Array.from(tags);
}
function processRow(row) {
const transactionType = (row[COL.TYPE] || '').trim();
if (transactionType === SKIP_TYPE) return null;
const { reason, card } = processReasonAndCard(row[COL.REASON]);
const payee = (row[COL.PAYEE] || '').trim();
const payerAccount = (row[COL.ACCT] || '').trim();
const debitBgn = parseNum(row[COL.DEBIT]);
const creditBgn = parseNum(row[COL.CREDIT]);
const date = parseDate(row[COL.DATE]);
const autoTags = generateTags({ reason, transactionType, payee, debitBgn, creditBgn });
const amount = debitBgn ?? creditBgn ?? null;
const rawMessage = [
row[COL.DATE] && `Date: ${row[COL.DATE]}`,
transactionType && `Type: ${transactionType}`,
payee && `Payee: ${payee}`,
debitBgn != null && `Debit: ${debitBgn} BGN`,
creditBgn != null && `Credit: ${creditBgn} BGN`,
].filter(Boolean).join(' | ');
return {
rawMessage,
date,
type: null,
card,
recipient: payee || null,
amount,
currency: 'BGN',
balance: null,
source: 'UPLOAD',
debitBgn,
creditBgn,
transactionType: transactionType || null,
payerAccount: payerAccount || null,
autoTags,
};
}
/**
* Parse a Buffer containing a DSK Bank CSV (cp1251 or UTF-8).
* Returns { rows, skipped, errors }.
*/
async function parseDskCsv(buffer) {
// Try cp1251 first (DSK Bank export encoding), fall back to UTF-8
let text = iconv.decode(buffer, 'cp1251');
if (!text.includes(COL.DATE)) {
text = buffer.toString('utf-8');
}
return new Promise((resolve, reject) => {
const rows = [];
const errors = [];
let skipped = 0;
const parser = parse(text, {
columns: true,
skip_empty_lines: true,
trim: true,
relax_column_count: true,
});
parser.on('readable', () => {
let record;
while ((record = parser.read()) !== null) {
try {
const row = processRow(record);
if (row === null) { skipped++; } else { rows.push(row); }
} catch (err) {
errors.push(err.message);
}
}
});
parser.on('error', reject);
parser.on('end', () => resolve({ rows, skipped, errors }));
});
}
module.exports = { parseDskCsv };
Write
index.js
index.js
39 lines
const express = require('express');
const cors = require('cors');
const morgan = require('morgan');
const rateLimit = require('express-rate-limit');
const { authentikMiddleware } = require('./auth');
const paymentsRouter = require('./routes/payments');
const uploadRouter = require('./routes/upload');
const app = express();
const PORT = process.env.PORT || 3001;
app.use(cors());
app.use(express.json({ limit: '16kb' }));
app.use(morgan('combined'));
// Rate-limit the public ingest endpoint before auth middleware
const ingestLimiter = rateLimit({
windowMs: 60 * 1000,
max: 200,
standardHeaders: true,
legacyHeaders: false,
message: { error: 'Too many requests, slow down' },
});
app.use('/api/payments/ingest', ingestLimiter);
// Authentik header auth (skips /api/health and /api/payments/ingest)
app.use(authentikMiddleware);
app.get('/api/health', (_req, res) => {
res.json({ status: 'ok', timestamp: new Date().toISOString() });
});
app.use('/api/payments', paymentsRouter);
app.use('/api/upload', uploadRouter);
app.listen(PORT, '[IP_ADDRESS]', () => {
console.log(`Finance Hub API running on port ${PORT}`);
});
Update Todos
Create folder structure and root config files
Write backend Prisma schema and migration
Write backend package.json and Dockerfile
Write backend src files (auth, parser, csvParser, index)
Write backend routes (payments.js, upload.js)
Write frontend config files
Write frontend React components
Build and verify with docker compose
Write
payments.js...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
11898
|
530
|
43
|
2026-05-09T07:13:43.386622+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-09/1778 /Users/lukas/.screenpipe/data/data/2026-05-09/1778310823386_m2.jpg...
|
Code
|
Design new payment-logge… — finance [SSH: nas]
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Explorer (⇧⌘E)
Search (⇧⌘F)
Source Control (⌃⇧ Explorer (⇧⌘E)
Search (⇧⌘F)
Source Control (⌃⇧G)
Run and Debug (⇧⌘D)
Remote Explorer
Extensions (⇧⌘X) - 2 require update
2
Claude Code
Containers
EXPLORER
EXPLORER
Explorer Section: finance [SSH: nas]
Explorer Section: finance [SSH: nas]
FINANCE [SSH: NAS]
auth
dsk-uploader
finance-hub
backend
frontend
.env
.env.example
.gitignore
docker-compose.yml
payments-logger
Outline Section
OUTLINE
OUTLINE
Timeline Section
TIMELINE
TIMELINE
docker-compose.yml, Editor Group 1
.env, Editor Group 1
report(1).csv, Editor Group 1
"Дата","Основание","Наредител/Получател","Номер сметка на наредителя / получателя","Вид на трансакцията","Свързваща референция","Валутен курс","Сума във валутата на превода","Дебит EUR","Кредит EUR"
"08.05.2026","400915xxxxxx4447 ПОС 08.05.2026 18:46<br/>Авт. код: 36C1UB","","","","","","","5,02",""
"08.05.2026","400915xxxxxx4447 ПОС 08.05.2026 18:36<br/>Авт. код: 5CK9TB","","","","","","","15,46",""
"08.05.2026","400915xxxxxx4447 ПОС 08.05.2026 18:07<br/>Авт. код: 8FK4TB","","","","","","","9,04",""
"08.05.2026","400915xxxxxx4447 ПЛАЩАНЕ НА ПОС 08.05.2026 19:32<br/>Авт. код: 6NM31C<br/>Номер на у-во: V5411421","BGR SOFIYA LIDL BALGARIYA EOOD UL TODOR","","КАРТОВА ОПЕРАЦИЯ","","","","67,81",""
"08.05.2026","400915xxxxxx4447 ПЛАЩАНЕ НА ПОС 07.05.2026 09:02<br/>Авт. код: 7NE8N7<br/>Номер на у-во: 10101446","BGR SOFIA CBA EKO MARKET","","КАРТОВА ОПЕРАЦИЯ","","","","5,51",""
"08.05.2026","400915xxxxxx4447 ПЛАЩАНЕ НА ПОС 06.05.2026 13:16<br/>Авт. код: 1TV886<br/>Номер на у-во: 06030191","POL BALICE Lagardere Travel R KR3","","КАРТОВА ОПЕРАЦИЯ","","","","5,49",""
"Дата","Основание","Наредител/Получател","Номер сметка на наредителя / получателя","Вид на трансакцията","Свързваща референция","Валутен курс","Сума във валутата на превода","Дебит EUR","Кредит EUR"
"08.05.2026","400915xxxxxx4447 ПОС 08.05.2026 18:46<br/>Авт. код: 36C1UB","","","","","","","5,02",""
"08.05.2026","400915xxxxxx4447 ПОС 08.05.2026 18:36<br/>Авт. код: 5CK9TB","","","","","","","15,46",""
"08.05.2026","400915xxxxxx4447 ПОС 08.05.2026 18:07<br/>Авт. код: 8FK4TB","","","","","","","9,04",""
"08.05.2026","400915xxxxxx4447 ПЛАЩАНЕ НА ПОС 08.05.2026 19:32<br/>Авт. код: 6NM31C<br/>Номер на у-во: V5411421","BGR SOFIYA LIDL BALGARIYA EOOD UL TODOR","","КАРТОВА ОПЕРАЦИЯ","","","","67,81",""
"08.05.2026","400915xxxxxx4447 ПЛАЩАНЕ НА ПОС 07.05.2026 09:02<br/>Авт. код: 7NE8N7<br/>Номер на у-во: 10101446","BGR SOFIA CBA EKO MARKET","","КАРТОВА ОПЕРАЦИЯ","","","","5,51",""
"08.05.2026","400915xxxxxx4447 ПЛАЩАНЕ НА ПОС 06.05.2026 13:16<br/>Авт. код: 1TV886<br/>Номер на у-во: 06030191","POL BALICE Lagardere Travel R KR3","","КАРТОВА ОПЕРАЦИЯ","","","","5,49",""
Design new payment-logge…, Editor Group 2
remote SSH: nas
SSH: nas
No Problems
0
0
No Ports Forwarded
0
Notifications
Sign In
Sign In
Info: Do you want to install the recommended 'Rainbow CSV' extension from mechatroner for report(1).csv?
Design new payment-logger and dsk-uploader hybrid app
Session history
New session
Message actions
payments.js
payments.js
ets create a new app that should be combination of payment-logger and dsk-uploader. It should have authorization via authentik (auth folder). All three folders (payment-logger, dsk-uploader and auth) are just refference these will be removed later. Auth project is separated it lives on its own. First reveiw them and see how these should be combined. It will be whole new app (also the folder name). Think very carefully of whatr these two apps do and how cold they be combined. THerer should be common db and uploader should store data the same way the /ingest does. It should be properly marked in UI if it is upload or ingest or both. FIrst think of tech stack and plan carefully.
Thinking
Thinking
I'll explore all three reference projects in parallel to understand their structure before planning.
Agent:
Explore payment-logger app structure and functionality
IN
Explore the /volume2/docker/finance/payments-logger directory thoroughly. I need to understand:
1. Tech stack (frontend framework, backend framework, database)
2. What the app does - its core purpose and features
3. Database schema - all tables, relationships
4. API routes - all endpoints, their purpose and request/response shapes
5. How data flows (ingest, storage, retrieval)
6. Any auth/middleware setup
7. Docker/deployment setup
8. Key files and their roles
Report with: directory structure, tech stack summary, database schema details, all API endpoints listed, UI features, and how data is ingested. Be thorough on the /ingest endpoint specifically.
Agent:
Explore dsk-uploader app structure and functionality
IN
Explore the /volume2/docker/finance/dsk-uploader directory thoroughly. I need to understand:
1. Tech stack (frontend framework, backend framework, database)
2. What the app does - its core purpose and features
3. Database schema - all tables, relationships
4. API routes - all endpoints, their purpose and request/response shapes
5. How file uploads work - what files, what format, how parsed
6. Any auth/middleware setup
7. Docker/deployment setup
8. Key files and their roles
Report with: directory structure, tech stack summary, database schema details, all API endpoints listed, UI features, how file upload parsing works, and what data is extracted from uploads. Be very thorough about the data model and what fields are stored.
Agent:
Explore auth folder and authentik integration
IN
Explore the /volume2/docker/finance/auth directory thoroughly. I need to understand:
1. What auth system is being used (Authentik)
2. How authentication/authorization is implemented - OAuth2, OIDC, session tokens, JWT?
3. Middleware - how is auth enforced on routes?
4. Any frontend auth flow - login redirect, token handling, protected routes
5. Environment variables related to auth
6. Docker/deployment setup for the auth service itself
7. Any example of how other apps integrate with this auth
Report with: directory structure, auth flow description, middleware code, environment variable names, and integration patterns. This is a reference for building auth into a new combined app.
Message actions
payments.js
payments.js
continue
Thinking
Thinking
Launching parallel exploration of all three reference projects.
Agent:
Explore payment-logger app structure
IN
Explore the /volume2/docker/finance/payments-logger directory thoroughly. I need to understand:
1. Full directory structure (tree)
2. Tech stack (frontend framework, backend framework, database, etc.)
3. What the app does - its core functionality
4. How data is ingested (look at /ingest route especially)
5. Database schema (what tables/collections exist)
6. API routes and their purposes
7. Frontend pages and components
8. Docker setup
9. Any auth/session handling
Please read key files: package.json files, main entry points, route files, database schema files, docker-compose.yml, and any frontend components. Be thorough - I need a complete picture to plan a new combined app.
Agent:
Explore dsk-uploader app structure
IN
Explore the /volume2/docker/finance/dsk-uploader directory thoroughly. I need to understand:
1. Full directory structure (tree)
2. Tech stack (frontend framework, backend framework, database, etc.)
3. What the app does - its core functionality
4. How file uploads work (what format, what processing happens)
5. Database schema (what tables/collections exist)
6. API routes and their purposes
7. Frontend pages and components
8. Docker setup
9. Any auth/session handling
Please read key files: package.json files, main entry points, route files, database schema files, docker-compose.yml, and any frontend components. Be thorough - I need a complete picture to plan a new combined app.
Agent:
Explore auth project structure
IN
Explore the /volume2/docker/finance/auth directory thoroughly. I need to understand:
1. Full directory structure (tree)
2. What authentication system is used (authentik integration details)
3. How OAuth/OIDC flow works
4. Any middleware or helper functions for protecting routes
5. Session management approach
6. How frontend handles auth state
7. Any example of how other apps integrate with this auth system
8. Docker setup and environment variables
Please read all files carefully - this auth system will be integrated into a new combined app. I need to understand exactly how to use it.
Thinking
Thinking
Now I have a complete picture of all three. Let me design the plan.
Agent:
Design combined app architecture
IN
Design a detailed implementation plan for a new combined web app that merges two existing applications. Here is full context:
---
## App 1: payments-logger (Node.js)
- **Purpose**: Ingest Bulgarian bank SMS → parse → store in PostgreSQL → review/tag/notify in React UI
- **Stack**: Node.js 20 + Express + Prisma 5 + PostgreSQL 16 + React 18 + Vite + Tailwind CSS
- **Auth**: Custom JWT (bcryptjs + jose), tokens in localStorage
- **Ingest**: POST /api/payments/ingest (public) — SMS text OR structured JSON (Apple Wallet)
- **Schema** (PostgreSQL via Prisma):
- `payments` table: id, raw_message, date, type (POS/ATM/INTERNET/ECOM/P2P/WALLET), card, recipient, amount, balance, status (UNPROCESSED/SENT/SKIPPED), notifyPhone, notifiedAt, created_at, updated_at
- `tags` table: id, name, color — M2M with payments via `_PaymentToTag`
- `users` table: id, username, hashed_password (this will be REMOVED)
- **UI**: Single-page React app — PaymentTable (sortable, filterable, taggable), FilterBar, status actions (send/skip), notification system
- **Parser** (backend/src/parser.js): Regex parser for Bulgarian DSK Bank SMS, extracts date/time (DD/MM/YYYY HH:MM), card mask, transaction type, recipient, amount, balance
## App 2: dsk-uploader (Python/Flask)
- **Purpose**: Upload DSK bank CSV exports → parse/normalize → upload to Notion database
- **Stack**: Python 3.11 + Flask + Pandas + Custom Notion SDK + Bootstrap 5
- **Auth**: None (open)
- **CSV format** (DSK Bank Bulgarian format, columns):
- `Дата` (date, DD.MM.YYYY)
- `Вид на трансакцията` (transaction type, Bulgarian)
- `Основание` (reason/description — contains card number regex: `^\d{6}x{6}\d{4}$`)
- `Дебит BGN` (debit amount, may be empty)
- `Кредит BGN` (credit amount, may be empty)
- `Наредител/Получател` (orderer/recipient name)
- `Номер сметка на наредителя / получателя` (account number)
- **Processing**: merge multiple CSVs, normalize dates, extract card numbers from reason via regex, auto-generate tags (keyword heuristics: ЗАПЛАТА→Salary, NETFLIX→Subscriptions, etc.), filter internal transfers
- **Output**: Notion database pages (this will be REPLACED with local PostgreSQL)
## App 3: auth (Authentik)
- **Mode**: Proxy mode via NPM (forward auth)
- **How it works**: NPM intercepts all requests, calls Authentik outpost's auth endpoint. On success, NPM injects headers into proxied request:
- `X-authentik-username`
- `X-authentik-email`
- `X-authentik-groups`
- **No code integration needed** in the app itself — just trust these headers from NPM
- **Logout**: Redirect user to `/outpost.goauthentik.io/sign_out`
---
## What the New Combined App Must Do
1. **Single PostgreSQL database** for all transactions
2. **SMS Ingest** (public endpoint) — same as payments-logger /ingest, source=INGEST
3. **CSV Upload** (authenticated) — parse DSK CSV files, store transactions with source=UPLOAD into the same DB schema
4. **Unified UI** — show all payments in one table regardless of source
5. **Source indicator** in UI — badge showing "INGEST", "UPLOAD", or "BOTH" (if duplicate detection added)
6. **Source filter** in FilterBar — filter by All/Ingest/Upload
7. **Authentik auth** — remove custom JWT entirely; trust X-authentik-* headers from NPM
8. **All existing payments-logger features**: tagging, send notification, skip, status tracking, filters, sorting, pagination
9. **Remove Notion dependency entirely** — all data stays in local PostgreSQL
---
## Technical Constraints
- Keep Node.js backend (not Python) — extend payments-logger's stack
- CSV parsing: use `csv-parse` npm package (handles encoding, streaming)
- File upload: use `multer` npm middleware
- Auth middleware: read X-authentik-username header, 401 if missing (but /api/payments/ingest stays public)
- Add `source` enum field (INGEST/UPLOAD) to payments schema
- Add `currency` field (EUR for SMS ingest, BGN for CSV uploads) — or just store as-is
- Remove `users` table from schema
---
## Please Design
1. Complete folder structure for the new app (suggest name: "finance-hub" or similar — note this is a placeholder, user will confirm)
2. Prisma schema with new fields (`source`, `currency`)
3. All backend API routes
4. CSV parser design in Node.js (port of the Python logic)
5. Authentik auth middleware
6. Frontend component structure (React) — what's reused from payments-logger, what's new
7. Docker Compose setup
8. Environment variables needed
9. Step-by-step implementation order
10. Verification checklist
Be specific about file paths and code structure. This will be used to write actual implementation code.
Thinking
Thinking
Good plan. Let me ask the one thing I need before writing the final plan.
AskUserQuestion
OUT
User has answered your questions: "What should the new combined app be called? This will be the folder name under /volume2/docker/finance/ and the app branding."="finance-hub". You can now continue with the user's answers in mind.
Thinking
Thinking
Writing the final plan now.
Thinking
Thinking
Write
ets-create-a-new-generic-sun.md
ets-create-a-new-generic-sun.md
326 lines
# finance-hub — Implementation Plan
## Context
Two separate finance apps exist as references and will be retired:
- **payments-logger** (Node.js/React): Ingests Bulgarian bank SMS notifications, stores payments in PostgreSQL, provides a review/tag/notify UI.
- **dsk-uploader** (Python/Flask): Uploads DSK bank CSV exports, parses them, sends to Notion.
The new app **finance-hub** (`/volume2/docker/finance/finance-hub/`) replaces both with a single unified system: all transactions (SMS-ingested and CSV-uploaded) land in one PostgreSQL database and one React UI. Authentication is delegated entirely to Authentik (proxy mode via NPM — no custom JWT).
---
## Tech Stack
| Layer | Choice | Rationale |
|-------|--------|-----------|
| Backend | Node.js 20 + Express + Prisma 5 | Extends payments-logger; no Python needed |
| CSV parsing | `csv-parse` + `iconv-lite` | Handles Bulgarian cp1251 encoding, RFC4180 quoted fields |
| File upload | `multer` (memory storage) | Bank CSVs are small (<500 KB), no disk cleanup needed |
| Database | PostgreSQL 16 | Same as payments-logger |
| Frontend | React 18 + Vite + Tailwind CSS + Lucide React | Same as payments-logger |
| Auth | Authentik proxy via NPM headers | No custom JWT; removes users table entirely |
| Container | Docker Compose | Same pattern as both reference apps |
**Removed vs payments-logger:** `bcryptjs`, `jose`, `users` table, login form, JWT storage.
**Removed vs dsk-uploader:** Python/Flask, Pandas, Notion SDK, all Notion references.
**Added:** `csv-parse`, `iconv-lite`, `multer`, `source` + `currency` fields, `UploadPanel` component.
---
## Folder Structure
```
/volume2/docker/finance/finance-hub/
├── docker-compose.yml
├── .env
├── .env.example
├── .gitignore
├── backend/
│ ├── Dockerfile
│ ├── package.json
│ ├── prisma/
│ │ ├── schema.prisma
│ │ └── migrations/
│ │ ├── migration_lock.toml
│ │ └── 20260508_init/
│ │ └── migration.sql
│ └── src/
│ ├── index.js ← entry point (Authentik middleware wired here)
│ ├── auth.js ← Authentik header middleware (replaces JWT auth)
│ ├── parser.js ← SMS parser (copy verbatim from payments-logger)
│ ├── csvParser.js ← NEW: DSK CSV parser (port of Python dskuploader.py)
│ └── routes/
│ ├── payments.js ← existing routes + source/currency additions
│ └── upload.js ← NEW: POST /api/upload/csv
└── frontend/
├── Dockerfile
├── package.json
├── vite.config.js
├── tailwind.config.js
├── postcss.config.js
├── index.html
└── src/
├── main.jsx ← remove AuthProvider wrapper
├── index.css
├── App.jsx ← remove auth state, add Upload tab toggle
└── components/
├── FilterBar.jsx ← add source filter select
├── PaymentTable.jsx ← add Source badge column + currency display
├── PaymentCard.jsx ← minor source badge addition
├── PaymentList.jsx ← unchanged
└── UploadPanel.jsx ← NEW: drag-and-drop CSV upload UI
```
---
## Database Schema (Prisma)
File: `backend/prisma/schema.prisma`
```prisma
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model Payment {
id Int @id @default(autoincrement())
rawMessage String @map("raw_message")
date DateTime?
type String?
card String?
recipient String?
amount Float?
currency String? @default("EUR")
balance Float?
source Source @default(INGEST)
status Status @default(UNPROCESSED)
tags Tag[]
notifiedAt DateTime? @map("notified_at")
notifyPhone String? @map("notify_phone")
debitBgn Float? @map("debit_bgn")
creditBgn Float? @map("credit_bgn")
transactionType String? @map("transaction_type")
payerAccount String? @map("payer_account")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@map("payments")
}
model Tag {
id Int @id @default(autoincrement())
name String @unique
color String @default("#6b7280")
payments Payment[]
@@map("tags")
}
enum Status { UNPROCESSED SENT SKIPPED }
enum Source { INGEST UPLOAD }
```
**Key decisions:**
- No `User` model — Authentik owns identity.
- `currency`: `EUR` for SMS ingest, `BGN` for CSV uploads.
- `debitBgn`, `creditBgn`, `transactionType`, `payerAccount`: nullable CSV-only columns; INGEST rows store nulls. Avoids a union query for the unified list view.
- `balance` is always null for CSV rows (DSK export does not include running balance).
- Fresh consolidated migration — no data migration from reference apps required.
---
## API Routes
| Method | Path | Auth | Description |
|--------|------|------|-------------|
| GET | /api/health | public | Health check |
| POST | /api/payments/ingest | public | SMS or structured ingest (source=INGEST) |
| GET | /api/payments | required | List with filters/sort/pagination (+ source filter) |
| GET | /api/payments/meta/tags | required | All tags |
| GET | /api/payments/meta/filters | required | Filter options incl. `sources` array |
| GET | /api/payments/:id | required | Single payment |
| PATCH | /api/payments/:id | required | Update status |
| DELETE | /api/payments/:id | required | Delete |
| POST | /api/payments/:id/send | required | Send notification |
| POST | /api/payments/:id/skip | required | Skip |
| POST | /api/payments/:id/tags | required | Add/upsert tag |
| DELETE | /api/payments/:id/tags/:tagId | required | Remove tag |
| POST | /api/upload/csv | required | DSK CSV file upload (source=UPLOAD) |
---
## Key Implementation Details
### auth.js (replaces entire old auth module)
```js
const PUBLIC_PATHS = new Set(['/api/health', '/api/payments/ingest']);
function authentikMiddleware(req, res, next) {
if (PUBLIC_PATHS.has(req.path)) return next();
const username = req.headers['x-authentik-username'];
if (!username) return res.status(401).json({ error: 'Unauthorized' });
req.user = {
username,
email: req.headers['x-authentik-email'] || null,
groups: (req.headers['x-authentik-groups'] || '').split(',').map(g => g.trim()).filter(Boolean),
};
next();
}
module.exports = { authentikMiddleware };
```
### csvParser.js (port of dskuploader.py)
- `iconv-lite` decodes buffer as cp1251 (DSK Bank export encoding), falls back to UTF-8
- `csv-parse` parses the decoded text with `columns: true`
- Columns: `Дата`, `Вид на трансакцията`, `Основание`, `Дебит BGN`, `Кредит BGN`, `Наредител/Получател`, `Номер сметка на наредителя / получателя`
- Card extraction: regex `/^\d{6}x{6}\d{4}$/` on first token of `Основание`
- Skips rows where `Вид на трансакцията === 'ТРАНСФЕР СОБСТВЕНИ СМЕТКИ'`
- Auto-tags via keyword rules (ЗАПЛАТА→Salary, LIDL→Groceries, NETFLIX→Subscriptions, etc.) — same logic as Python `generate_tags()`
- Returns `{ rows: PaymentData[], skipped: number, errors: string[] }`
### payments.js changes from payments-logger
1. Add `source: 'INGEST'` and `currency` to the `/ingest` create call
2. Add `source` to the `GET /` where clause filter
3. Add `sources` to `meta/filters` response
4. Currency-aware amount formatting in notification message
5. Remove all JWT/auth references (no `/auth/register`, `/auth/login`)
### upload.js (new)
- `multer` memory storage, max 10 files × 10 MB
- Calls `parseDskCsv(buffer)` per file
- Upserts tags via `prisma.tag.upsert` then connects
- Returns `{ imported, skipped, errors, payments[] }`
### Frontend changes
- **Delete**: `auth.js`, `AuthProvider.jsx`
- **main.jsx**: Remove `<AuthProvider>` wrapper
- **App.jsx**: Replace `authFetch` with plain `fetch` (Authentik session cookie travels automatically); logout → `window.location.href = '/outpost.goauthentik.io/sign_out'`; add "Payments" / "Upload CSV" tab toggle
- **FilterBar.jsx**: Add source `<select>` (All / SMS Ingest / CSV Upload); widen grid to 5 cols
- **PaymentTable.jsx**: Add `Source` column with `SMS` (indigo) / `CSV` (emerald) badge; show `${amount} ${currency}` in amount cell
- **UploadPanel.jsx** (new): Drag-and-drop zone + file list + import button + result summary with error accordion; calls `POST /api/upload/csv` with `FormData`
---
## Docker Compose
```yaml
services:
db:
image: postgres:16-alpine
environment: { POSTGRES_USER: finance, POSTGRES_PASSWORD: [PASSWORD] POSTGRES_DB: finance_hub }
volumes: [pgdata:/var/lib/postgresql/data]
healthcheck: { test: pg_isready -U finance -d finance_hub, interval: 5s }
backend:
build: ./backend
environment:
DATABASE_URL: [CONNECTION_STRING]
PORT: "3001"
NOTIFIER_URL: ${NOTIFIER_URL}
NOTIFIER_CHANNEL: ${NOTIFIER_CHANNEL:-viber}
NOTIFY_DEFAULT_PHONE: ${NOTIFY_DEFAULT_PHONE}
TZ: ${TZ:-Europe/Sofia}
ports: ["${BACKEND_PORT:-3001}:3001"]
depends_on: { db: { condition: service_healthy } }
frontend:
build: ./frontend
ports: ["${FRONTEND_PORT:-5175}:5173"]
depends_on: [backend]
volumes: { pgdata: }
```
**NPM setup:** Frontend port proxied through Authentik forward auth. Backend port exposed separately (unprotected) so the public `/api/payments/ingest` remains reachable by iOS Shortcuts / SMS gateways without login.
---
## Environment Variables (.env)
```bash
[ENV_SECRET]
NOTIFIER_URL=[URL_WITH_CREDENTIALS] @default(autoincrement())
rawMessage String @map("raw_message")
date DateTime?
type String?
card String?
recipient String?
amount Float?
currency String? @default("EUR")
balance Float?
source Source @default(INGEST)
status Status @default(UNPROCESSED)
tags Tag[]
notifiedAt DateTime? @map("notified_at")
notifyPhone String? @map("notify_phone")
debitBgn Float? @map("debit_bgn")
creditBgn Float? @map("credit_bgn")
transactionType String? @map("transaction_type")
payerAccount String? @map("payer_account")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@map("payments")
}
model Tag {
id Int @id @default(autoincrement())
name String @unique
color String @default("#6b7280")
payments Payment[]
@@map("tags")
}
enum Status {
UNPROCESSED
SENT
SKIPPED
}
enum Source {
INGEST
UPLOAD
}
Write
migration.sql
migration.sql
55 lines
-- CreateEnum
CREATE TYPE "Status" AS ENUM ('UNPROCESSED', 'SENT', 'SKIPPED');
CREATE TYPE "Source" AS ENUM ('INGEST', 'UPLOAD');
-- CreateTable
CREATE TABLE "payments" (
"id" SERIAL PRIMARY KEY,
"raw_message" TEXT NOT NULL,
"date" TIMESTAMP(3),
"type" TEXT,
"card" TEXT,
"recipient" TEXT,
"amount" DOUBLE PRECISION,
"currency" TEXT DEFAULT 'EUR',
"balance" DOUBLE PRECISION,
"source" "Source" NOT NULL DEFAULT 'INGEST',
"status" "Status" NOT NULL DEFAULT 'UNPROCESSED',
"notified_at" TIMESTAMP(3),
"notify_phone" TEXT,
"debit_bgn" DOUBLE PRECISION,
"credit_bgn" DOUBLE PRECISION,
"transaction_type" TEXT,
"payer_account" TEXT,
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP
);
-- CreateTable
CREATE TABLE "tags" (
"id" SERIAL PRIMARY KEY,
"name" TEXT NOT NULL,
"color" TEXT NOT NULL DEFAULT '#6b7280'
);
-- CreateUniqueIndex
CREATE UNIQUE INDEX "tags_name_key" ON "tags"("name");
-- CreateTable (M2M join)
CREATE TABLE "_PaymentToTag" (
"A" INTEGER NOT NULL,
"B" INTEGER NOT NULL,
CONSTRAINT "_PaymentToTag_AB_pkey" PRIMARY KEY ("A", "B")
);
CREATE INDEX "_PaymentToTag_B_index" ON "_PaymentToTag"("B");
-- AddForeignKey
ALTER TABLE "_PaymentToTag"
ADD CONSTRAINT "_PaymentToTag_A_fkey"
FOREIGN KEY ("A") REFERENCES "payments"("id") ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE "_PaymentToTag"
ADD CONSTRAINT "_PaymentToTag_B_fkey"
FOREIGN KEY ("B") REFERENCES "tags"("id") ON DELETE CASCADE ON UPDATE CASCADE;
Write
migration_lock.toml
migration_lock.toml
4 lines
# Please do not edit this file manually
# It should be added in your version-control system (e.g., Git)
provider = "postgresql"
Update Todos
Create folder structure and root config files
Write backend Prisma schema and migration
Write backend package.json and Dockerfile
Write backend src files (auth, parser, csvParser, index)
Write backend routes (payments.js, upload.js)
Write frontend config files
Write frontend React components
Build and verify with docker compose
Write
package.json
package.json
26 lines
{
"name": "finance-hub-backend",
"version": "1.0.0",
"main": "src/index.js",
"scripts": {
"start": "node src/index.js",
"dev": "nodemon src/index.js",
"prisma:generate": "prisma generate",
"prisma:migrate": "prisma migrate deploy"
},
"dependencies": {
"@prisma/client": "^5.22.0",
"cors": "^2.8.5",
"csv-parse": "^5.5.6",
"express": "^4.21.1",
"express-rate-limit": "^7.4.0",
"iconv-lite": "^0.6.3",
"morgan": "^1.10.0",
"multer": "^1.4.5-lts.1"
},
"devDependencies": {
"nodemon": "^3.1.7",
"prisma": "^5.22.0"
}
}
Write
Dockerfile
Dockerfile
18 lines
FROM node:20-alpine
RUN apk add --no-cache openssl
WORKDIR /app
COPY package.json package-lock.json* ./
RUN npm install
COPY prisma ./prisma
RUN npx prisma generate
COPY src ./src
EXPOSE 3001
CMD ["sh", "-c", "npx prisma migrate deploy && node src/index.js"]
Update Todos
Create folder structure and root config files
Write backend Prisma schema and migration
Write backend package.json and Dockerfile
Write backend src files (auth, parser, csvParser, index)
Write backend routes (payments.js, upload.js)
Write frontend config files
Write frontend React components
Build and verify with docker compose
Write
auth.js
auth.js
27 lines
const PUBLIC_PATHS = new Set([
'/api/health',
'/api/payments/ingest',
]);
function authentikMiddleware(req, res, next) {
if (PUBLIC_PATHS.has(req.path)) return next();
const username = req.headers['x-authentik-username'];
if (!username) {
return res.status(401).json({ error: 'Unauthorized — missing Authentik session' });
}
req.user = {
username,
email: req.headers['x-authentik-email'] || null,
groups: (req.headers['x-authentik-groups'] || '')
.split(',')
.map(g => g.trim())
.filter(Boolean),
};
next();
}
module.exports = { authentikMiddleware };
Write
parser.js
parser.js
104 lines
/**
* Parses SMS payment messages from Bulgarian banks (DSK Bank, etc.)
*
* Supported formats:
*
* POS / INTERNET / ECOM / P2P payment:
* DSK Bank. Na DD/MM/YYYY v HH:MM sa plateni AMOUNT CURRENCY s karta CARD na POS s adres: RECIPIENT. Nalichni: BALANCE CURRENCY.
*
* ATM withdrawal:
* DSK Bank. Na DD/MM/YYYY v HH:MM sa iztegleni AMOUNT CURRENCY s karta CARD ot ATM s adres: RECIPIENT. Nalichni: BALANCE CURRENCY.
*
* ATM utility payment (amount may include fee as AMOUNT/FEE):
* DSK Bank. Na DD/MM/YYYY v HH:MM sa plateni AMOUNT CURRENCY/FEE CURRENCY s karta CARD na ATM s adres:RECIPIENT. Nalichni: BALANCE CURRENCY.
*/
const LOCAL_TZ = process.env.TZ || 'Europe/Sofia';
/**
* Convert a local-timezone date/time to a UTC Date object.
* Uses Intl to resolve the actual UTC offset (DST-aware).
*/
function localToUtc(year, month, day, hour, minute) {
const naive = new Date(Date.UTC(year, month - 1, day, hour, minute, 0));
const formatter = new Intl.DateTimeFormat('en-US', {
timeZone: LOCAL_TZ,
year: 'numeric', month: '2-digit', day: '2-digit',
hour: '2-digit', minute: '2-digit', second: '2-digit',
hour12: false,
});
const parts = {};
formatter.formatToParts(naive).forEach(p => { parts[p.type] = p.value; });
const localAtNaive = new Date(Date.UTC(
parseInt(parts.year), parseInt(parts.month) - 1, parseInt(parts.day),
parseInt(parts.hour) % 24, parseInt(parts.minute), parseInt(parts.second),
));
const offsetMs = localAtNaive.getTime() - naive.getTime();
return new Date(Date.UTC(year, month - 1, day, hour, minute, 0) - offsetMs);
}
function parsePaymentSms(message) {
const result = {
rawMessage: message,
date: null,
type: null,
card: null,
recipient: null,
amount: null,
balance: null,
};
// Date and time: "Na DD/MM/YYYY v HH:MM"
const dateMatch = message.match(/Na (\d{2})\/(\d{2})\/(\d{4}) v (\d{2}):(\d{2})/i);
if (dateMatch) {
const [, day, month, year, hour, minute] = dateMatch;
result.date = localToUtc(
parseInt(year), parseInt(month), parseInt(day),
parseInt(hour), parseInt(minute),
);
}
// Card mask: "s karta 400915***4447" or "s karta 483890***7162"
const cardMatch = message.match(/s karta\s+([\d*]+)/i);
if (cardMatch) {
result.card = cardMatch[1];
}
// Transaction type: supports both prepositions
// "na POS" / "na ATM" / "na INTERNET" etc. (payment)
// "ot ATM" (withdrawal)
const typeMatch = message.match(/(?:na|ot)\s+(POS|ATM|INTERNET|ECOM|P2P)\b/i);
if (typeMatch) {
result.type = typeMatch[1].toUpperCase();
}
// Recipient address: "s adres: MERCHANT" or "s adres:MERCHANT" (no space variant)
const recipientMatch = message.match(/s adres:\s*([^.]+)\./i);
if (recipientMatch) {
result.recipient = recipientMatch[1].trim();
}
// Amount: handles both verbs and the AMOUNT/FEE suffix format
// "sa plateni 7.78 EUR"
// "sa iztegleni 400.00 EUR"
// "sa plateni 0.50 EUR/0.50 EUR" → captures 0.50 (the charged amount, ignoring fee)
const amountMatch = message.match(/sa (?:plateni|iztegleni)\s+([\d.,]+)\s+[A-Z]{3}/i);
if (amountMatch) {
result.amount = parseFloat(amountMatch[1].replace(',', '.'));
}
// Balance: "Nalichni: 2583.07 EUR."
const balanceMatch = message.match(/Nalichni:\s*([\d.,]+)\s+[A-Z]{3}/i);
if (balanceMatch) {
result.balance = parseFloat(balanceMatch[1].replace(',', '.'));
}
return result;
}
module.exports = { parsePaymentSms };
Write
csvParser.js
csvParser.js
175 lines
/**
* DSK Bank CSV parser — Node.js port of dskuploader.py
*
* DSK Bank exports use Windows-1251 (cp1251) encoding.
* Each row maps to a Payment record with source=UPLOAD, currency=BGN.
*/
const { parse } = require('csv-parse');
const iconv = require('iconv-lite');
const SKIP_TYPE = 'ТРАНСФЕР СОБСТВЕНИ СМЕТКИ';
const CARD_REGEX = /^\d{6}x{6}\d{4}$/;
const POS_REGEX = /^\s*ПЛАЩАНЕ\s+НА\s+ПОС\s+\d{2}\.\d{2}\.\d{4}\s+\d{2}:\d{2}/;
const COL = {
DATE: 'Дата',
TYPE: 'Вид на трансакцията',
REASON: 'Основание',
DEBIT: 'Дебит BGN',
CREDIT: 'Кредит BGN',
PAYEE: 'Наредител/Получател',
ACCT: 'Номер сметка на наредителя / получателя',
};
const TAG_RULES = [
['reason', 'ЗАПЛАТА', 'Salary'],
['reason', 'ТЕГЛЕНЕ НА ATM', 'ATM'],
['reason', 'ПЛАЩАНЕ ПО ЗАЕМ', 'Home Credit'],
['reason', 'АВТ.ТАКСА ОБСЛУЖВАНЕ', 'Bills'],
['transactionType', 'КОМУНАЛНИ УСЛУГИ', 'Bills'],
['payee', 'VIVACOM', 'Subscriptions'],
['payee', 'Google', 'Subscriptions'],
['payee', 'SkyShowtime', 'Subscriptions'],
['payee', 'NETFLIX', 'Subscriptions'],
['payee', 'LUKOIL', 'Bills'],
['payee', 'CityGate', 'Bills'],
['payee', 'CBA', 'Groceries'],
['payee', 'FANTASTICO', 'Groceries'],
['payee', 'LIDL', 'Groceries'],
];
function parseNum(val) {
if (val == null || val === '') return null;
if (typeof val === 'number') return isNaN(val) ? null : val;
const s = String(val).trim().replace(/\xa0/g, '').replace(/ /g, '').replace(',', '.');
const n = parseFloat(s);
return isNaN(n) ? null : n;
}
function parseDate(val) {
if (!val) return null;
const s = String(val).trim();
const m = s.match(/^(\d{2})\.(\d{2})\.(\d{4})$/);
if (m) {
return new Date(Date.UTC(parseInt(m[3]), parseInt(m[2]) - 1, parseInt(m[1])));
}
return null;
}
function processReasonAndCard(reason) {
if (!reason || typeof reason !== 'string') return { reason: '', card: null };
const parts = reason.trim().split(' ');
let card = null;
let cleanReason = reason.trim();
if (parts[0] && CARD_REGEX.test(parts[0])) {
card = parts[0];
cleanReason = parts.slice(1).join(' ').trim();
}
if (POS_REGEX.test(cleanReason)) {
const posParts = cleanReason.split('<br/>');
try {
const dateTime = posParts[0].split('ПОС ')[1];
cleanReason = `POS PAYMENT ${dateTime}`;
} catch (_) { /* keep original */ }
}
return { reason: cleanReason.replace(/\s+/g, ' ').trim(), card };
}
function generateTags(fields) {
const tags = new Set();
for (const [field, keyword, tagName] of TAG_RULES) {
if ((fields[field] || '').includes(keyword)) {
tags.add(tagName);
}
}
return Array.from(tags);
}
function processRow(row) {
const transactionType = (row[COL.TYPE] || '').trim();
if (transactionType === SKIP_TYPE) return null;
const { reason, card } = processReasonAndCard(row[COL.REASON]);
const payee = (row[COL.PAYEE] || '').trim();
const payerAccount = (row[COL.ACCT] || '').trim();
const debitBgn = parseNum(row[COL.DEBIT]);
const creditBgn = parseNum(row[COL.CREDIT]);
const date = parseDate(row[COL.DATE]);
const autoTags = generateTags({ reason, transactionType, payee, debitBgn, creditBgn });
const amount = debitBgn ?? creditBgn ?? null;
const rawMessage = [
row[COL.DATE] && `Date: ${row[COL.DATE]}`,
transactionType && `Type: ${transactionType}`,
payee && `Payee: ${payee}`,
debitBgn != null && `Debit: ${debitBgn} BGN`,
creditBgn != null && `Credit: ${creditBgn} BGN`,
].filter(Boolean).join(' | ');
return {
rawMessage,
date,
type: null,
card,
recipient: payee || null,
amount,
currency: 'BGN',
balance: null,
source: 'UPLOAD',
debitBgn,
creditBgn,
transactionType: transactionType || null,
payerAccount: payerAccount || null,
autoTags,
};
}
/**
* Parse a Buffer containing a DSK Bank CSV (cp1251 or UTF-8).
* Returns { rows, skipped, errors }.
*/
async function parseDskCsv(buffer) {
// Try cp1251 first (DSK Bank export encoding), fall back to UTF-8
let text = iconv.decode(buffer, 'cp1251');
if (!text.includes(COL.DATE)) {
text = buffer.toString('utf-8');
}
return new Promise((resolve, reject) => {
const rows = [];
const errors = [];
let skipped = 0;
const parser = parse(text, {
columns: true,
skip_empty_lines: true,
trim: true,
relax_column_count: true,
});
parser.on('readable', () => {
let record;
while ((record = parser.read()) !== null) {
try {
const row = processRow(record);
if (row === null) { skipped++; } else { rows.push(row); }
} catch (err) {
errors.push(err.message);
}
}
});
parser.on('error', reject);
parser.on('end', () => resolve({ rows, skipped, errors }));
});
}
module.exports = { parseDskCsv };
Write
index.js
index.js
39 lines
const express = require('express');
const cors = require('cors');
const morgan = require('morgan');
const rateLimit = require('express-rate-limit');
const { authentikMiddleware } = require('./auth');
const paymentsRouter = require('./routes/payments');
const uploadRouter = require('./routes/upload');
const app = express();
const PORT = process.env.PORT || 3001;
app.use(cors());
app.use(express.json({ limit: '16kb' }));
app.use(morgan('combined'));
// Rate-limit the public ingest endpoint before auth middleware
const ingestLimiter = rateLimit({
windowMs...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Explorer (⇧⌘E)","depth":19,"bounds":{"left":0.0,"top":0.047885075,"width":0.015957447,"height":0.03830806},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":true},{"role":"AXStaticText","text":"","depth":22,"bounds":{"left":0.0039893617,"top":0.057462092,"width":0.007978723,"height":0.01915403},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Search (⇧⌘F)","depth":19,"bounds":{"left":0.0,"top":0.08619314,"width":0.015957447,"height":0.03830806},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"bounds":{"left":0.0039893617,"top":0.09577015,"width":0.007978723,"height":0.01915403},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Source Control (⌃⇧G)","depth":19,"bounds":{"left":0.0,"top":0.1245012,"width":0.015957447,"height":0.03830806},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"bounds":{"left":0.0039893617,"top":0.13407822,"width":0.007978723,"height":0.01915403},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Run and Debug (⇧⌘D)","depth":19,"bounds":{"left":0.0,"top":0.16280925,"width":0.015957447,"height":0.03830806},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"bounds":{"left":0.0039893617,"top":0.17238627,"width":0.007978723,"height":0.01915403},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Remote Explorer","depth":19,"bounds":{"left":0.0,"top":0.20111732,"width":0.015957447,"height":0.03830806},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"bounds":{"left":0.0039893617,"top":0.21069433,"width":0.007978723,"height":0.01915403},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Extensions (⇧⌘X) - 2 require update","depth":19,"bounds":{"left":0.0,"top":0.23942538,"width":0.015957447,"height":0.03830806},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"bounds":{"left":0.0039893617,"top":0.2490024,"width":0.007978723,"height":0.01915403},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"2","depth":22,"bounds":{"left":0.009640957,"top":0.2601756,"width":0.0019946808,"height":0.008778931},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Claude Code","depth":19,"bounds":{"left":0.0,"top":0.27773345,"width":0.015957447,"height":0.03830806},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"Containers","depth":19,"bounds":{"left":0.0,"top":0.3160415,"width":0.015957447,"height":0.03830806},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"EXPLORER","depth":17,"bounds":{"left":0.022606382,"top":0.047885075,"width":0.018949468,"height":0.02793296},"on_screen":true,"role_description":"heading"},{"role":"AXStaticText","text":"EXPLORER","depth":18,"bounds":{"left":0.022606382,"top":0.056664005,"width":0.018949468,"height":0.0103751},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.022606382,"top":0.056664005,"width":0.0023271276,"height":0.0103751}},{"char_start":1,"char_count":7,"bounds":{"left":0.024933511,"top":0.056664005,"width":0.01662234,"height":0.0103751}}],"role_description":"text"},{"role":"AXButton","text":"Explorer Section: finance [SSH: nas]","depth":21,"bounds":{"left":0.015957447,"top":0.07581804,"width":0.09940159,"height":0.017557861},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.01662234,"top":0.07821229,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXHeading","text":"Explorer Section: finance [SSH: nas]","depth":22,"bounds":{"left":0.022606382,"top":0.07581804,"width":0.039228722,"height":0.017557861},"on_screen":true,"role_description":"heading"},{"role":"AXStaticText","text":"FINANCE [SSH: NAS]","depth":23,"bounds":{"left":0.022606382,"top":0.079010375,"width":0.039228722,"height":0.0103751},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.022606382,"top":0.07980846,"width":0.0023271276,"height":0.0103751}},{"char_start":1,"char_count":17,"bounds":{"left":0.024933511,"top":0.07980846,"width":0.036901597,"height":0.0103751}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.09577015,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"auth","depth":27,"bounds":{"left":0.025930852,"top":0.09577015,"width":0.008976064,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.096568234,"width":0.0023271276,"height":0.011971269}},{"char_start":1,"char_count":3,"bounds":{"left":0.02825798,"top":0.096568234,"width":0.0066489363,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.11332801,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"dsk-uploader","depth":27,"bounds":{"left":0.025930852,"top":0.11332801,"width":0.026928192,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.11412609,"width":0.0026595744,"height":0.011971269}},{"char_start":1,"char_count":11,"bounds":{"left":0.028590426,"top":0.11412609,"width":0.024268618,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.13088587,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"finance-hub","depth":27,"bounds":{"left":0.025930852,"top":0.13088587,"width":0.024268618,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.13168396,"width":0.0016622341,"height":0.011971269}},{"char_start":1,"char_count":10,"bounds":{"left":0.027593086,"top":0.13168396,"width":0.022938829,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.022273935,"top":0.14844373,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"backend","depth":27,"bounds":{"left":0.028590426,"top":0.14844373,"width":0.017287234,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.028590426,"top":0.14924182,"width":0.0026595744,"height":0.011971269}},{"char_start":1,"char_count":6,"bounds":{"left":0.03125,"top":0.14924182,"width":0.01462766,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.022273935,"top":0.1660016,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"frontend","depth":27,"bounds":{"left":0.028590426,"top":0.1660016,"width":0.017287234,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.028590426,"top":0.16679968,"width":0.0016622341,"height":0.011971269}},{"char_start":1,"char_count":7,"bounds":{"left":0.03025266,"top":0.16679968,"width":0.015625,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.021276595,"top":0.1819633,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":".env","depth":27,"bounds":{"left":0.028590426,"top":0.18355946,"width":0.00831117,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.028590426,"top":0.18435754,"width":0.0013297872,"height":0.011971269}},{"char_start":1,"char_count":3,"bounds":{"left":0.029920213,"top":0.18435754,"width":0.006981383,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.021276595,"top":0.19952115,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":".env.example","depth":27,"bounds":{"left":0.028590426,"top":0.20111732,"width":0.025930852,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.028590426,"top":0.2019154,"width":0.0013297872,"height":0.011971269}},{"char_start":1,"char_count":11,"bounds":{"left":0.029920213,"top":0.2019154,"width":0.024933511,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.021276595,"top":0.21707901,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":".gitignore","depth":27,"bounds":{"left":0.028590426,"top":0.21867518,"width":0.018949468,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.028590426,"top":0.21947326,"width":0.0013297872,"height":0.011971269}},{"char_start":1,"char_count":9,"bounds":{"left":0.029920213,"top":0.21947326,"width":0.017952127,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.021276595,"top":0.23463687,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"docker-compose.yml","depth":27,"bounds":{"left":0.028590426,"top":0.23623304,"width":0.042220745,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.028590426,"top":0.23703113,"width":0.0026595744,"height":0.011971269}},{"char_start":1,"char_count":17,"bounds":{"left":0.03125,"top":0.23703113,"width":0.03956117,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.25379092,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"payments-logger","depth":27,"bounds":{"left":0.025930852,"top":0.25379092,"width":0.034574468,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.254589,"width":0.0026595744,"height":0.011971269}},{"char_start":1,"char_count":14,"bounds":{"left":0.028590426,"top":0.254589,"width":0.031914894,"height":0.011971269}}],"role_description":"text"},{"role":"AXButton","text":"Outline Section","depth":21,"bounds":{"left":0.015957447,"top":0.9473264,"width":0.09940159,"height":0.017557861},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.01662234,"top":0.9497207,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXHeading","text":"OUTLINE","depth":22,"bounds":{"left":0.022606382,"top":0.9473264,"width":0.01662234,"height":0.017557861},"on_screen":true,"role_description":"heading"},{"role":"AXStaticText","text":"OUTLINE","depth":23,"bounds":{"left":0.022606382,"top":0.95131683,"width":0.01662234,"height":0.0103751},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.022606382,"top":0.95131683,"width":0.0029920214,"height":0.0103751}},{"char_start":1,"char_count":6,"bounds":{"left":0.025598405,"top":0.95131683,"width":0.013630319,"height":0.0103751}}],"role_description":"text"},{"role":"AXButton","text":"Timeline Section","depth":21,"bounds":{"left":0.015957447,"top":0.9648843,"width":0.09940159,"height":0.017557861},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.01662234,"top":0.96727854,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXHeading","text":"TIMELINE","depth":22,"bounds":{"left":0.022606382,"top":0.9648843,"width":0.01761968,"height":0.017557861},"on_screen":true,"role_description":"heading"},{"role":"AXStaticText","text":"TIMELINE","depth":23,"bounds":{"left":0.022606382,"top":0.9688747,"width":0.01761968,"height":0.0103751},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.022606382,"top":0.9688747,"width":0.0026595744,"height":0.0103751}},{"char_start":1,"char_count":7,"bounds":{"left":0.025265958,"top":0.9688747,"width":0.015292553,"height":0.0103751}}],"role_description":"text"},{"role":"AXRadioButton","text":"docker-compose.yml, Editor Group 1","depth":28,"bounds":{"left":0.11569149,"top":0.047885075,"width":0.0625,"height":0.02793296},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":".env, Editor Group 1","depth":28,"bounds":{"left":0.17785904,"top":0.047885075,"width":0.040226065,"height":0.02793296},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"report(1).csv, Editor Group 1","depth":28,"bounds":{"left":0.21775267,"top":0.047885075,"width":0.046210106,"height":0.02793296},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"","depth":29,"bounds":{"left":0.13264628,"top":0.07821229,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":29,"bounds":{"left":0.14827128,"top":0.07821229,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":29,"bounds":{"left":0.17586437,"top":0.07821229,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"\"Дата\",\"Основание\",\"Наредител/Получател\",\"Номер сметка на наредителя / получателя\",\"Вид на трансакцията\",\"Свързваща референция\",\"Валутен курс\",\"Сума във валутата на превода\",\"Дебит EUR\",\"Кредит EUR\"\n\"08.05.2026\",\"400915xxxxxx4447 ПОС 08.05.2026 18:46<br/>Авт. код: 36C1UB\",\"\",\"\",\"\",\"\",\"\",\"\",\"5,02\",\"\"\n\"08.05.2026\",\"400915xxxxxx4447 ПОС 08.05.2026 18:36<br/>Авт. код: 5CK9TB\",\"\",\"\",\"\",\"\",\"\",\"\",\"15,46\",\"\"\n\"08.05.2026\",\"400915xxxxxx4447 ПОС 08.05.2026 18:07<br/>Авт. код: 8FK4TB\",\"\",\"\",\"\",\"\",\"\",\"\",\"9,04\",\"\"\n\"08.05.2026\",\"400915xxxxxx4447 ПЛАЩАНЕ НА ПОС 08.05.2026 19:32<br/>Авт. код: 6NM31C<br/>Номер на у-во: V5411421\",\"BGR SOFIYA LIDL BALGARIYA EOOD UL TODOR\",\"\",\"КАРТОВА ОПЕРАЦИЯ\",\"\",\"\",\"\",\"67,81\",\"\"\n\"08.05.2026\",\"400915xxxxxx4447 ПЛАЩАНЕ НА ПОС 07.05.2026 09:02<br/>Авт. код: 7NE8N7<br/>Номер на у-во: 10101446\",\"BGR SOFIA CBA EKO MARKET\",\"\",\"КАРТОВА ОПЕРАЦИЯ\",\"\",\"\",\"\",\"5,51\",\"\"\n\"08.05.2026\",\"400915xxxxxx4447 ПЛАЩАНЕ НА ПОС 06.05.2026 13:16<br/>Авт. код: 1TV886<br/>Номер на у-во: 06030191\",\"POL BALICE Lagardere Travel R KR3\",\"\",\"КАРТОВА ОПЕРАЦИЯ\",\"\",\"\",\"\",\"5,49\",\"\"","depth":28,"bounds":{"left":0.13763298,"top":0.0933759,"width":0.42021278,"height":0.014365523},"on_screen":true,"value":"\"Дата\",\"Основание\",\"Наредител/Получател\",\"Номер сметка на наредителя / получателя\",\"Вид на трансакцията\",\"Свързваща референция\",\"Валутен курс\",\"Сума във валутата на превода\",\"Дебит EUR\",\"Кредит EUR\"\n\"08.05.2026\",\"400915xxxxxx4447 ПОС 08.05.2026 18:46<br/>Авт. код: 36C1UB\",\"\",\"\",\"\",\"\",\"\",\"\",\"5,02\",\"\"\n\"08.05.2026\",\"400915xxxxxx4447 ПОС 08.05.2026 18:36<br/>Авт. код: 5CK9TB\",\"\",\"\",\"\",\"\",\"\",\"\",\"15,46\",\"\"\n\"08.05.2026\",\"400915xxxxxx4447 ПОС 08.05.2026 18:07<br/>Авт. код: 8FK4TB\",\"\",\"\",\"\",\"\",\"\",\"\",\"9,04\",\"\"\n\"08.05.2026\",\"400915xxxxxx4447 ПЛАЩАНЕ НА ПОС 08.05.2026 19:32<br/>Авт. код: 6NM31C<br/>Номер на у-во: V5411421\",\"BGR SOFIYA LIDL BALGARIYA EOOD UL TODOR\",\"\",\"КАРТОВА ОПЕРАЦИЯ\",\"\",\"\",\"\",\"67,81\",\"\"\n\"08.05.2026\",\"400915xxxxxx4447 ПЛАЩАНЕ НА ПОС 07.05.2026 09:02<br/>Авт. код: 7NE8N7<br/>Номер на у-во: 10101446\",\"BGR SOFIA CBA EKO MARKET\",\"\",\"КАРТОВА ОПЕРАЦИЯ\",\"\",\"\",\"\",\"5,51\",\"\"\n\"08.05.2026\",\"400915xxxxxx4447 ПЛАЩАНЕ НА ПОС 06.05.2026 13:16<br/>Авт. код: 1TV886<br/>Номер на у-во: 06030191\",\"POL BALICE Lagardere Travel R KR3\",\"\",\"КАРТОВА ОПЕРАЦИЯ\",\"\",\"\",\"\",\"5,49\",\"\"","role_description":"editor","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"\"Дата\",\"Основание\",\"Наредител/Получател\",\"Номер сметка на наредителя / получателя\",\"Вид на трансакцията\",\"Свързваща референция\",\"Валутен курс\",\"Сума във валутата на превода\",\"Дебит EUR\",\"Кредит EUR\"\n\"08.05.2026\",\"400915xxxxxx4447 ПОС 08.05.2026 18:46<br/>Авт. код: 36C1UB\",\"\",\"\",\"\",\"\",\"\",\"\",\"5,02\",\"\"\n\"08.05.2026\",\"400915xxxxxx4447 ПОС 08.05.2026 18:36<br/>Авт. код: 5CK9TB\",\"\",\"\",\"\",\"\",\"\",\"\",\"15,46\",\"\"\n\"08.05.2026\",\"400915xxxxxx4447 ПОС 08.05.2026 18:07<br/>Авт. код: 8FK4TB\",\"\",\"\",\"\",\"\",\"\",\"\",\"9,04\",\"\"\n\"08.05.2026\",\"400915xxxxxx4447 ПЛАЩАНЕ НА ПОС 08.05.2026 19:32<br/>Авт. код: 6NM31C<br/>Номер на у-во: V5411421\",\"BGR SOFIYA LIDL BALGARIYA EOOD UL TODOR\",\"\",\"КАРТОВА ОПЕРАЦИЯ\",\"\",\"\",\"\",\"67,81\",\"\"\n\"08.05.2026\",\"400915xxxxxx4447 ПЛАЩАНЕ НА ПОС 07.05.2026 09:02<br/>Авт. код: 7NE8N7<br/>Номер на у-во: 10101446\",\"BGR SOFIA CBA EKO MARKET\",\"\",\"КАРТОВА ОПЕРАЦИЯ\",\"\",\"\",\"\",\"5,51\",\"\"\n\"08.05.2026\",\"400915xxxxxx4447 ПЛАЩАНЕ НА ПОС 06.05.2026 13:16<br/>Авт. код: 1TV886<br/>Номер на у-во: 06030191\",\"POL BALICE Lagardere Travel R KR3\",\"\",\"КАРТОВА ОПЕРАЦИЯ\",\"\",\"\",\"\",\"5,49\",\"\"","depth":29,"bounds":{"left":0.13763298,"top":0.09497207,"width":0.42021278,"height":0.012769354},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.13763298,"top":0.09497207,"width":0.0023271276,"height":0.011173184}},{"char_start":1,"char_count":199,"bounds":{"left":0.13763298,"top":0.09497207,"width":0.47573137,"height":0.025538707}},{"char_start":200,"char_count":109,"bounds":{"left":0.13763298,"top":0.10933759,"width":0.25964096,"height":0.025538707}},{"char_start":309,"char_count":110,"bounds":{"left":0.13763298,"top":0.123703115,"width":0.26196808,"height":0.025538707}},{"char_start":419,"char_count":109,"bounds":{"left":0.13763298,"top":0.13806863,"width":0.25964096,"height":0.025538707}},{"char_start":528,"char_count":211,"bounds":{"left":0.13763298,"top":0.15243416,"width":0.5043218,"height":0.025538707}},{"char_start":739,"char_count":194,"bounds":{"left":0.13763298,"top":0.16679968,"width":0.4637633,"height":0.025538707}},{"char_start":933,"char_count":202,"bounds":{"left":0.13996011,"top":0.1811652,"width":0.48537233,"height":0.011173184}}],"role_description":"text"},{"role":"AXRadioButton","text":"Design new payment-logge…, Editor Group 2","depth":28,"bounds":{"left":0.5578458,"top":0.047885075,"width":0.07912234,"height":0.02793296},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXButton","text":"remote SSH: nas","depth":16,"bounds":{"left":0.0006648936,"top":0.98244214,"width":0.028590426,"height":0.01755786},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":17,"bounds":{"left":0.0033244682,"top":0.9848364,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"SSH: nas","depth":17,"bounds":{"left":0.008643617,"top":0.9856345,"width":0.017952127,"height":0.011173184},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.008643617,"top":0.9856345,"width":0.0013297872,"height":0.011173184}},{"char_start":1,"char_count":7,"bounds":{"left":0.009973404,"top":0.9856345,"width":0.01462766,"height":0.011173184}}],"role_description":"text"},{"role":"AXButton","text":"No Problems","depth":16,"bounds":{"left":0.03025266,"top":0.98244214,"width":0.022606382,"height":0.01755786},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":17,"bounds":{"left":0.031914894,"top":0.9848364,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"0","depth":17,"bounds":{"left":0.03723404,"top":0.9856345,"width":0.004986702,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":17,"bounds":{"left":0.041888297,"top":0.9848364,"width":0.0056515955,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"0","depth":17,"bounds":{"left":0.04720745,"top":0.9856345,"width":0.0039893617,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"No Ports Forwarded","depth":16,"bounds":{"left":0.054521278,"top":0.98244214,"width":0.012632979,"height":0.01755786},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":17,"bounds":{"left":0.05618351,"top":0.9848364,"width":0.0056515955,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"0","depth":17,"bounds":{"left":0.061502658,"top":0.9856345,"width":0.0039893617,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Notifications","depth":16,"bounds":{"left":0.9886968,"top":0.98244214,"width":0.010638298,"height":0.01755786},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sign In","depth":16,"bounds":{"left":0.9650931,"top":0.98244214,"width":0.022606382,"height":0.01755786},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":17,"bounds":{"left":0.96675533,"top":0.9848364,"width":0.0056515955,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Sign In","depth":17,"bounds":{"left":0.97207445,"top":0.9856345,"width":0.013962766,"height":0.011173184},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.97207445,"top":0.9856345,"width":0.0013297872,"height":0.011173184}},{"char_start":1,"char_count":6,"bounds":{"left":0.9734042,"top":0.9856345,"width":0.010638298,"height":0.011173184}}],"role_description":"text"},{"role":"AXStaticText","text":"Info: Do you want to install the recommended 'Rainbow CSV' extension from mechatroner for report(1).csv?","depth":12,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Design new payment-logger and dsk-uploader hybrid app","depth":19,"bounds":{"left":0.55984044,"top":0.08060654,"width":0.099734046,"height":0.022346368},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Session history","depth":19,"bounds":{"left":0.9780585,"top":0.08060654,"width":0.00930851,"height":0.022346368},"on_screen":true,"help_text":"Session history","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New session","depth":19,"bounds":{"left":0.9886968,"top":0.08060654,"width":0.00930851,"height":0.022346368},"on_screen":true,"help_text":"New session","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Message actions","depth":24,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"payments.js","depth":23,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"payments.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ets create a new app that should be combination of payment-logger and dsk-uploader. It should have authorization via authentik (auth folder). All three folders (payment-logger, dsk-uploader and auth) are just refference these will be removed later. Auth project is separated it lives on its own. First reveiw them and see how these should be combined. It will be whole new app (also the folder name). Think very carefully of whatr these two apps do and how cold they be combined. THerer should be common db and uploader should store data the same way the /ingest does. It should be properly marked in UI if it is upload or ingest or both. FIrst think of tech stack and plan carefully.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":23,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Thinking","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"I'll explore all three reference projects in parallel to understand their structure before planning.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Agent:","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Explore payment-logger app structure and functionality","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Explore the /volume2/docker/finance/payments-logger directory thoroughly. I need to understand:\n1. Tech stack (frontend framework, backend framework, database)\n2. What the app does - its core purpose and features\n3. Database schema - all tables, relationships\n4. API routes - all endpoints, their purpose and request/response shapes\n5. How data flows (ingest, storage, retrieval)\n6. Any auth/middleware setup\n7. Docker/deployment setup\n8. Key files and their roles\n\nReport with: directory structure, tech stack summary, database schema details, all API endpoints listed, UI features, and how data is ingested. Be thorough on the /ingest endpoint specifically.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Agent:","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Explore dsk-uploader app structure and functionality","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Explore the /volume2/docker/finance/dsk-uploader directory thoroughly. I need to understand:\n1. Tech stack (frontend framework, backend framework, database)\n2. What the app does - its core purpose and features\n3. Database schema - all tables, relationships\n4. API routes - all endpoints, their purpose and request/response shapes\n5. How file uploads work - what files, what format, how parsed\n6. Any auth/middleware setup\n7. Docker/deployment setup\n8. Key files and their roles\n\nReport with: directory structure, tech stack summary, database schema details, all API endpoints listed, UI features, how file upload parsing works, and what data is extracted from uploads. Be very thorough about the data model and what fields are stored.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Agent:","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Explore auth folder and authentik integration","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Explore the /volume2/docker/finance/auth directory thoroughly. I need to understand:\n1. What auth system is being used (Authentik)\n2. How authentication/authorization is implemented - OAuth2, OIDC, session tokens, JWT?\n3. Middleware - how is auth enforced on routes?\n4. Any frontend auth flow - login redirect, token handling, protected routes\n5. Environment variables related to auth\n6. Docker/deployment setup for the auth service itself\n7. Any example of how other apps integrate with this auth\n\nReport with: directory structure, auth flow description, middleware code, environment variable names, and integration patterns. This is a reference for building auth into a new combined app.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Message actions","depth":24,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"payments.js","depth":23,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"payments.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"continue","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":23,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Thinking","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Launching parallel exploration of all three reference projects.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Agent:","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Explore payment-logger app structure","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Explore the /volume2/docker/finance/payments-logger directory thoroughly. I need to understand:\n1. Full directory structure (tree)\n2. Tech stack (frontend framework, backend framework, database, etc.)\n3. What the app does - its core functionality\n4. How data is ingested (look at /ingest route especially)\n5. Database schema (what tables/collections exist)\n6. API routes and their purposes\n7. Frontend pages and components\n8. Docker setup\n9. Any auth/session handling\n\nPlease read key files: package.json files, main entry points, route files, database schema files, docker-compose.yml, and any frontend components. Be thorough - I need a complete picture to plan a new combined app.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Agent:","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Explore dsk-uploader app structure","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Explore the /volume2/docker/finance/dsk-uploader directory thoroughly. I need to understand:\n1. Full directory structure (tree)\n2. Tech stack (frontend framework, backend framework, database, etc.)\n3. What the app does - its core functionality\n4. How file uploads work (what format, what processing happens)\n5. Database schema (what tables/collections exist)\n6. API routes and their purposes\n7. Frontend pages and components\n8. Docker setup\n9. Any auth/session handling\n\nPlease read key files: package.json files, main entry points, route files, database schema files, docker-compose.yml, and any frontend components. Be thorough - I need a complete picture to plan a new combined app.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Agent:","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Explore auth project structure","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Explore the /volume2/docker/finance/auth directory thoroughly. I need to understand:\n1. Full directory structure (tree)\n2. What authentication system is used (authentik integration details)\n3. How OAuth/OIDC flow works\n4. Any middleware or helper functions for protecting routes\n5. Session management approach\n6. How frontend handles auth state\n7. Any example of how other apps integrate with this auth system\n8. Docker setup and environment variables\n\nPlease read all files carefully - this auth system will be integrated into a new combined app. I need to understand exactly how to use it.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":23,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Thinking","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Now I have a complete picture of all three. Let me design the plan.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Agent:","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Design combined app architecture","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Design a detailed implementation plan for a new combined web app that merges two existing applications. Here is full context:\n\n---\n\n## App 1: payments-logger (Node.js)\n- **Purpose**: Ingest Bulgarian bank SMS → parse → store in PostgreSQL → review/tag/notify in React UI\n- **Stack**: Node.js 20 + Express + Prisma 5 + PostgreSQL 16 + React 18 + Vite + Tailwind CSS\n- **Auth**: Custom JWT (bcryptjs + jose), tokens in localStorage\n- **Ingest**: POST /api/payments/ingest (public) — SMS text OR structured JSON (Apple Wallet)\n- **Schema** (PostgreSQL via Prisma):\n - `payments` table: id, raw_message, date, type (POS/ATM/INTERNET/ECOM/P2P/WALLET), card, recipient, amount, balance, status (UNPROCESSED/SENT/SKIPPED), notifyPhone, notifiedAt, created_at, updated_at\n - `tags` table: id, name, color — M2M with payments via `_PaymentToTag`\n - `users` table: id, username, hashed_password (this will be REMOVED)\n- **UI**: Single-page React app — PaymentTable (sortable, filterable, taggable), FilterBar, status actions (send/skip), notification system\n- **Parser** (backend/src/parser.js): Regex parser for Bulgarian DSK Bank SMS, extracts date/time (DD/MM/YYYY HH:MM), card mask, transaction type, recipient, amount, balance\n\n## App 2: dsk-uploader (Python/Flask)\n- **Purpose**: Upload DSK bank CSV exports → parse/normalize → upload to Notion database\n- **Stack**: Python 3.11 + Flask + Pandas + Custom Notion SDK + Bootstrap 5\n- **Auth**: None (open)\n- **CSV format** (DSK Bank Bulgarian format, columns):\n - `Дата` (date, DD.MM.YYYY)\n - `Вид на трансакцията` (transaction type, Bulgarian)\n - `Основание` (reason/description — contains card number regex: `^\\d{6}x{6}\\d{4}$`)\n - `Дебит BGN` (debit amount, may be empty)\n - `Кредит BGN` (credit amount, may be empty)\n - `Наредител/Получател` (orderer/recipient name)\n - `Номер сметка на наредителя / получателя` (account number)\n- **Processing**: merge multiple CSVs, normalize dates, extract card numbers from reason via regex, auto-generate tags (keyword heuristics: ЗАПЛАТА→Salary, NETFLIX→Subscriptions, etc.), filter internal transfers\n- **Output**: Notion database pages (this will be REPLACED with local PostgreSQL)\n\n## App 3: auth (Authentik)\n- **Mode**: Proxy mode via NPM (forward auth)\n- **How it works**: NPM intercepts all requests, calls Authentik outpost's auth endpoint. On success, NPM injects headers into proxied request:\n - `X-authentik-username` \n - `X-authentik-email`\n - `X-authentik-groups`\n- **No code integration needed** in the app itself — just trust these headers from NPM\n- **Logout**: Redirect user to `/outpost.goauthentik.io/sign_out`\n\n---\n\n## What the New Combined App Must Do\n\n1. **Single PostgreSQL database** for all transactions\n2. **SMS Ingest** (public endpoint) — same as payments-logger /ingest, source=INGEST\n3. **CSV Upload** (authenticated) — parse DSK CSV files, store transactions with source=UPLOAD into the same DB schema\n4. **Unified UI** — show all payments in one table regardless of source\n5. **Source indicator** in UI — badge showing \"INGEST\", \"UPLOAD\", or \"BOTH\" (if duplicate detection added)\n6. **Source filter** in FilterBar — filter by All/Ingest/Upload\n7. **Authentik auth** — remove custom JWT entirely; trust X-authentik-* headers from NPM\n8. **All existing payments-logger features**: tagging, send notification, skip, status tracking, filters, sorting, pagination\n9. **Remove Notion dependency entirely** — all data stays in local PostgreSQL\n\n---\n\n## Technical Constraints\n\n- Keep Node.js backend (not Python) — extend payments-logger's stack\n- CSV parsing: use `csv-parse` npm package (handles encoding, streaming)\n- File upload: use `multer` npm middleware\n- Auth middleware: read X-authentik-username header, 401 if missing (but /api/payments/ingest stays public)\n- Add `source` enum field (INGEST/UPLOAD) to payments schema\n- Add `currency` field (EUR for SMS ingest, BGN for CSV uploads) — or just store as-is\n- Remove `users` table from schema\n\n---\n\n## Please Design\n\n1. Complete folder structure for the new app (suggest name: \"finance-hub\" or similar — note this is a placeholder, user will confirm)\n2. Prisma schema with new fields (`source`, `currency`)\n3. All backend API routes\n4. CSV parser design in Node.js (port of the Python logic)\n5. Authentik auth middleware\n6. Frontend component structure (React) — what's reused from payments-logger, what's new\n7. Docker Compose setup\n8. Environment variables needed\n9. Step-by-step implementation order\n10. Verification checklist\n\nBe specific about file paths and code structure. This will be used to write actual implementation code.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":23,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Thinking","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Good plan. Let me ask the one thing I need before writing the final plan.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskUserQuestion","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"User has answered your questions: \"What should the new combined app be called? This will be the folder name under /volume2/docker/finance/ and the app branding.\"=\"finance-hub\". You can now continue with the user's answers in mind.","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":23,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Thinking","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Writing the final plan now.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":23,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Thinking","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"ets-create-a-new-generic-sun.md","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"ets-create-a-new-generic-sun.md","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"326 lines","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"# finance-hub — Implementation Plan\n\n## Context\n\nTwo separate finance apps exist as references and will be retired:\n- **payments-logger** (Node.js/React): Ingests Bulgarian bank SMS notifications, stores payments in PostgreSQL, provides a review/tag/notify UI.\n- **dsk-uploader** (Python/Flask): Uploads DSK bank CSV exports, parses them, sends to Notion.\n\nThe new app **finance-hub** (`/volume2/docker/finance/finance-hub/`) replaces both with a single unified system: all transactions (SMS-ingested and CSV-uploaded) land in one PostgreSQL database and one React UI. Authentication is delegated entirely to Authentik (proxy mode via NPM — no custom JWT).\n\n---\n\n## Tech Stack\n\n| Layer | Choice | Rationale |\n|-------|--------|-----------|\n| Backend | Node.js 20 + Express + Prisma 5 | Extends payments-logger; no Python needed |\n| CSV parsing | `csv-parse` + `iconv-lite` | Handles Bulgarian cp1251 encoding, RFC4180 quoted fields |\n| File upload | `multer` (memory storage) | Bank CSVs are small (<500 KB), no disk cleanup needed |\n| Database | PostgreSQL 16 | Same as payments-logger |\n| Frontend | React 18 + Vite + Tailwind CSS + Lucide React | Same as payments-logger |\n| Auth | Authentik proxy via NPM headers | No custom JWT; removes users table entirely |\n| Container | Docker Compose | Same pattern as both reference apps |\n\n**Removed vs payments-logger:** `bcryptjs`, `jose`, `users` table, login form, JWT storage. \n**Removed vs dsk-uploader:** Python/Flask, Pandas, Notion SDK, all Notion references. \n**Added:** `csv-parse`, `iconv-lite`, `multer`, `source` + `currency` fields, `UploadPanel` component.\n\n---\n\n## Folder Structure\n\n```\n/volume2/docker/finance/finance-hub/\n├── docker-compose.yml\n├── .env\n├── .env.example\n├── .gitignore\n├── backend/\n│ ├── Dockerfile\n│ ├── package.json\n│ ├── prisma/\n│ │ ├── schema.prisma\n│ │ └── migrations/\n│ │ ├── migration_lock.toml\n│ │ └── 20260508_init/\n│ │ └── migration.sql\n│ └── src/\n│ ├── index.js ← entry point (Authentik middleware wired here)\n│ ├── auth.js ← Authentik header middleware (replaces JWT auth)\n│ ├── parser.js ← SMS parser (copy verbatim from payments-logger)\n│ ├── csvParser.js ← NEW: DSK CSV parser (port of Python dskuploader.py)\n│ └── routes/\n│ ├── payments.js ← existing routes + source/currency additions\n│ └── upload.js ← NEW: POST /api/upload/csv\n└── frontend/\n ├── Dockerfile\n ├── package.json\n ├── vite.config.js\n ├── tailwind.config.js\n ├── postcss.config.js\n ├── index.html\n └── src/\n ├── main.jsx ← remove AuthProvider wrapper\n ├── index.css\n ├── App.jsx ← remove auth state, add Upload tab toggle\n └── components/\n ├── FilterBar.jsx ← add source filter select\n ├── PaymentTable.jsx ← add Source badge column + currency display\n ├── PaymentCard.jsx ← minor source badge addition\n ├── PaymentList.jsx ← unchanged\n └── UploadPanel.jsx ← NEW: drag-and-drop CSV upload UI\n```\n\n---\n\n## Database Schema (Prisma)\n\nFile: `backend/prisma/schema.prisma`\n\n```prisma\ngenerator client {\n provider = \"prisma-client-js\"\n}\n\ndatasource db {\n provider = \"postgresql\"\n url = env(\"DATABASE_URL\")\n}\n\nmodel Payment {\n id Int @id @default(autoincrement())\n rawMessage String @map(\"raw_message\")\n date DateTime?\n type String?\n card String?\n recipient String?\n amount Float?\n currency String? @default(\"EUR\")\n balance Float?\n source Source @default(INGEST)\n status Status @default(UNPROCESSED)\n tags Tag[]\n notifiedAt DateTime? @map(\"notified_at\")\n notifyPhone String? @map(\"notify_phone\")\n debitBgn Float? @map(\"debit_bgn\")\n creditBgn Float? @map(\"credit_bgn\")\n transactionType String? @map(\"transaction_type\")\n payerAccount String? @map(\"payer_account\")\n createdAt DateTime @default(now()) @map(\"created_at\")\n updatedAt DateTime @updatedAt @map(\"updated_at\")\n\n @@map(\"payments\")\n}\n\nmodel Tag {\n id Int @id @default(autoincrement())\n name String @unique\n color String @default(\"#6b7280\")\n payments Payment[]\n\n @@map(\"tags\")\n}\n\nenum Status { UNPROCESSED SENT SKIPPED }\nenum Source { INGEST UPLOAD }\n```\n\n**Key decisions:**\n- No `User` model — Authentik owns identity.\n- `currency`: `EUR` for SMS ingest, `BGN` for CSV uploads.\n- `debitBgn`, `creditBgn`, `transactionType`, `payerAccount`: nullable CSV-only columns; INGEST rows store nulls. Avoids a union query for the unified list view.\n- `balance` is always null for CSV rows (DSK export does not include running balance).\n- Fresh consolidated migration — no data migration from reference apps required.\n\n---\n\n## API Routes\n\n| Method | Path | Auth | Description |\n|--------|------|------|-------------|\n| GET | /api/health | public | Health check |\n| POST | /api/payments/ingest | public | SMS or structured ingest (source=INGEST) |\n| GET | /api/payments | required | List with filters/sort/pagination (+ source filter) |\n| GET | /api/payments/meta/tags | required | All tags |\n| GET | /api/payments/meta/filters | required | Filter options incl. `sources` array |\n| GET | /api/payments/:id | required | Single payment |\n| PATCH | /api/payments/:id | required | Update status |\n| DELETE | /api/payments/:id | required | Delete |\n| POST | /api/payments/:id/send | required | Send notification |\n| POST | /api/payments/:id/skip | required | Skip |\n| POST | /api/payments/:id/tags | required | Add/upsert tag |\n| DELETE | /api/payments/:id/tags/:tagId | required | Remove tag |\n| POST | /api/upload/csv | required | DSK CSV file upload (source=UPLOAD) |\n\n---\n\n## Key Implementation Details\n\n### auth.js (replaces entire old auth module)\n```js\nconst PUBLIC_PATHS = new Set(['/api/health', '/api/payments/ingest']);\n\nfunction authentikMiddleware(req, res, next) {\n if (PUBLIC_PATHS.has(req.path)) return next();\n const username = req.headers['x-authentik-username'];\n if (!username) return res.status(401).json({ error: 'Unauthorized' });\n req.user = {\n username,\n email: req.headers['x-authentik-email'] || null,\n groups: (req.headers['x-authentik-groups'] || '').split(',').map(g => g.trim()).filter(Boolean),\n };\n next();\n}\nmodule.exports = { authentikMiddleware };\n```\n\n### csvParser.js (port of dskuploader.py)\n- `iconv-lite` decodes buffer as cp1251 (DSK Bank export encoding), falls back to UTF-8\n- `csv-parse` parses the decoded text with `columns: true`\n- Columns: `Дата`, `Вид на трансакцията`, `Основание`, `Дебит BGN`, `Кредит BGN`, `Наредител/Получател`, `Номер сметка на наредителя / получателя`\n- Card extraction: regex `/^\\d{6}x{6}\\d{4}$/` on first token of `Основание`\n- Skips rows where `Вид на трансакцията === 'ТРАНСФЕР СОБСТВЕНИ СМЕТКИ'`\n- Auto-tags via keyword rules (ЗАПЛАТА→Salary, LIDL→Groceries, NETFLIX→Subscriptions, etc.) — same logic as Python `generate_tags()`\n- Returns `{ rows: PaymentData[], skipped: number, errors: string[] }`\n\n### payments.js changes from payments-logger\n1. Add `source: 'INGEST'` and `currency` to the `/ingest` create call\n2. Add `source` to the `GET /` where clause filter\n3. Add `sources` to `meta/filters` response\n4. Currency-aware amount formatting in notification message\n5. Remove all JWT/auth references (no `/auth/register`, `/auth/login`)\n\n### upload.js (new)\n- `multer` memory storage, max 10 files × 10 MB\n- Calls `parseDskCsv(buffer)` per file\n- Upserts tags via `prisma.tag.upsert` then connects\n- Returns `{ imported, skipped, errors, payments[] }`\n\n### Frontend changes\n- **Delete**: `auth.js`, `AuthProvider.jsx`\n- **main.jsx**: Remove `<AuthProvider>` wrapper\n- **App.jsx**: Replace `authFetch` with plain `fetch` (Authentik session cookie travels automatically); logout → `window.location.href = '/outpost.goauthentik.io/sign_out'`; add \"Payments\" / \"Upload CSV\" tab toggle\n- **FilterBar.jsx**: Add source `<select>` (All / SMS Ingest / CSV Upload); widen grid to 5 cols\n- **PaymentTable.jsx**: Add `Source` column with `SMS` (indigo) / `CSV` (emerald) badge; show `${amount} ${currency}` in amount cell\n- **UploadPanel.jsx** (new): Drag-and-drop zone + file list + import button + result summary with error accordion; calls `POST /api/upload/csv` with `FormData`\n\n---\n\n## Docker Compose\n\n```yaml\nservices:\n db:\n image: postgres:16-alpine\n environment: { POSTGRES_USER: finance, POSTGRES_PASSWORD: ${DB_PASSWORD}, POSTGRES_DB: finance_hub }\n volumes: [pgdata:/var/lib/postgresql/data]\n healthcheck: { test: pg_isready -U finance -d finance_hub, interval: 5s }\n\n backend:\n build: ./backend\n environment:\n DATABASE_URL: postgresql://finance:${DB_PASSWORD}@db:5432/finance_hub\n PORT: \"3001\"\n NOTIFIER_URL: ${NOTIFIER_URL}\n NOTIFIER_CHANNEL: ${NOTIFIER_CHANNEL:-viber}\n NOTIFY_DEFAULT_PHONE: ${NOTIFY_DEFAULT_PHONE}\n TZ: ${TZ:-Europe/Sofia}\n ports: [\"${BACKEND_PORT:-3001}:3001\"]\n depends_on: { db: { condition: service_healthy } }\n\n frontend:\n build: ./frontend\n ports: [\"${FRONTEND_PORT:-5175}:5173\"]\n depends_on: [backend]\n\nvolumes: { pgdata: }\n```\n\n**NPM setup:** Frontend port proxied through Authentik forward auth. Backend port exposed separately (unprotected) so the public `/api/payments/ingest` remains reachable by iOS Shortcuts / SMS gateways without login.\n\n---\n\n## Environment Variables (.env)\n\n```bash\nDB_PASSWORD=change_me\nNOTIFIER_URL=https://notifier.lakylak.xyz\nNOTIFIER_CHANNEL=viber\nNOTIFY_DEFAULT_PHONE=+359000000000\nTZ=Europe/Sofia\nBACKEND_PORT=3001\nFRONTEND_PORT=5175\n```\n\nRemoved vs payments-logger: `JWT_SECRET`, `JWT_EXPIRE_MINUTES`.\n\n---\n\n## Implementation Order\n\n1. Create folder structure and write `docker-compose.yml`, `.env.example`, `.gitignore`\n2. Write `backend/prisma/schema.prisma` and migration SQL\n3. Write `backend/package.json` (add `csv-parse`, `iconv-lite`, `multer`; remove `bcryptjs`, `jose`)\n4. Write `backend/Dockerfile`\n5. Write `backend/src/auth.js` (Authentik middleware)\n6. Copy `backend/src/parser.js` verbatim from payments-logger\n7. Write `backend/src/csvParser.js` (Python port)\n8. Write `backend/src/routes/upload.js`\n9. Write `backend/src/routes/payments.js` (from payments-logger + 5 changes listed above)\n10. Write `backend/src/index.js`\n11. Copy frontend base from payments-logger; delete `auth.js` + `AuthProvider.jsx`\n12. Update `main.jsx`, `App.jsx`, `FilterBar.jsx`, `PaymentTable.jsx`\n13. Write `frontend/src/components/UploadPanel.jsx`\n14. Update `frontend/vite.config.js`\n15. `docker compose build && docker compose up -d`\n16. Run verification checklist\n\n---\n\n## Verification\n\n**Schema**\n- `payments` table has `source`, `currency`, `debit_bgn`, `credit_bgn`, `transaction_type`, `payer_account`\n- No `users` table; `Source` enum exists\n\n**Auth**\n- `GET /api/payments` → 401 without `x-authentik-username` header\n- `POST /api/payments/ingest` → 201 without any header\n- `curl -H \"x-authentik-username: test\" localhost:3001/api/payments` → 200\n\n**SMS Ingest**\n- DSK POS SMS → `source=INGEST`, `currency=EUR`, correct amount/card/recipient\n- Apple Wallet structured body → `type=WALLET`, `source=INGEST`\n- Rate limiter → 429 after 200 req/min\n\n**CSV Upload**\n- Single DSK CSV → rows with `source=UPLOAD`, `currency=BGN`\n- Multiple CSVs in one request → all merged\n- `ТРАНСФЕР СОБСТВЕНИ СМЕТКИ` rows counted in `skipped`, not imported\n- Card regex match from `Основание` column\n- Auto-tags applied (ЗАПЛАТА→Salary, LIDL→Groceries)\n- cp1251 file imports correctly\n\n**UI**\n- Source badge visible in payment table (SMS indigo, CSV emerald)\n- Source dropdown in FilterBar filters correctly\n- Amount shows correct currency per row\n- Upload Panel: drag-and-drop works, result summary shows counts\n- Logout redirects to Authentik sign_out\n- No login form shown (Authentik handles it at NPM level)\n- Tags, send, skip, delete all still work\n\n## Reference Files\n\n- `/volume2/docker/finance/payments-logger/backend/src/routes/payments.js`\n- `/volume2/docker/finance/payments-logger/backend/src/parser.js`\n- `/volume2/docker/finance/payments-logger/backend/src/index.js`\n- `/volume2/docker/finance/payments-logger/backend/src/auth.js`\n- `/volume2/docker/finance/payments-logger/backend/prisma/schema.prisma`\n- `/volume2/docker/finance/payments-logger/frontend/src/App.jsx`\n- `/volume2/docker/finance/payments-logger/frontend/src/components/PaymentTable.jsx`\n- `/volume2/docker/finance/payments-logger/frontend/src/components/FilterBar.jsx`\n- `/volume2/docker/finance/dsk-uploader/dskuploader.py`\n- `/volume2/docker/finance/auth/docker-compose.yml`","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Claude’s Plan","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"ets-create-a-new-generic-sun.md","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"ets-create-a-new-generic-sun.md","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Stayed in plan mode","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":23,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Thinking","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Good question. Here's the full breakdown:","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"Backend Tech Stack — Options","depth":22,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"Backend Tech Stack — Options","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"Option A: Node.js + Express + Prisma (my recommendation)","depth":22,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"Option A: Node.js + Express + Prisma (my recommendation)","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Why:","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"payments-logger is already Node.js/Express/Prisma. The new app is 80% payments-logger with CSV upload added on top. Keeping the same stack means:","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Copy","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"parser.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"verbatim, zero rewrite","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Copy the entire","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"routes/payments.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"with minimal edits","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Same Prisma schema workflow, same migrations, same Docker image","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"The CSV parsing logic (the only Python-specific thing) ports cleanly to","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"csv-parse","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"— it's just regex + string manipulation, nothing pandas-specific","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Trade-off:","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Have to port the Python CSV parsing to JS. It's ~150 lines and mostly string manipulation — straightforward.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"Option B: Python + FastAPI + SQLAlchemy","depth":22,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"Option B: Python + FastAPI + SQLAlchemy","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Rewrite everything in Python. dsk-uploader is Python, so CSV parsing is already done.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Pro:","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Keep the dsk-uploader CSV logic as-is (no porting). Python has better data science libraries if you later add analytics.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Con:","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Lose the entire payments-logger backend (routes, parser, Prisma schema) — full rewrite. FastAPI + SQLAlchemy is a different mental model than Express + Prisma. Frontend stays React anyway, so the stack split doesn't simplify anything.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Verdict:","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"More work overall, gains almost nothing.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"Option C: Hybrid microservices (Node.js backend + Python CSV service)","depth":22,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"Option C: Hybrid microservices (Node.js backend + Python CSV service)","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Keep Node.js as the main API, add a separate Python FastAPI service just for CSV parsing. They share the DB.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Pro:","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Zero porting — Python CSV code used as-is.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Con:","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Two backend services to maintain, deploy, and keep in sync. Inter-service HTTP calls. Two Dockerfiles. For ~150 lines of CSV logic, this is massively over-engineered.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Verdict:","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Not worth it.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"Option D: Python + Flask (exactly like dsk-uploader)","depth":22,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"Option D: Python + Flask (exactly like dsk-uploader)","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Extend dsk-uploader into a full payments app.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Pro:","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Pandas for CSV, no porting.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Con:","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Jinja2 templates instead of React (or add React separately). Would need to reimplement the entire payments-logger (SMS parser, notification system, tag management, pagination/filtering). Flask's Jinja templating is far less capable than the existing React UI. The React frontend is the stronger UI foundation.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Verdict:","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Worst of all options — rebuild the harder parts (UI, SMS parser, notification) for no gain.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"Summary","depth":22,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"Summary","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Option","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CSV porting effort","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"App rewrite effort","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Result quality","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"A (Node.js)","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Medium (150 lines)","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Minimal","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Best","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"B (Python FastAPI)","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"None","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"High (full backend)","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Worse","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"C (Hybrid)","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"None","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Low + infra overhead","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Overkill","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"D (Python Flask)","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"None","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Very high","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Worst","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Option","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"A (Node.js)","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"B (Python FastAPI)","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"C (Hybrid)","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"D (Python Flask)","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CSV porting effort","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Medium (150 lines)","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"None","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"None","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"None","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"App rewrite effort","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Minimal","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"High (full backend)","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Low + infra overhead","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Very high","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Result quality","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Best","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Worse","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Overkill","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Worst","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Option","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CSV porting effort","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"App rewrite effort","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Result quality","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"The CSV parser port (the only cost of Option A) is a one-time ~150 line exercise. Everything else in the plan reuses payments-logger code directly. That's why Node.js is the clear winner here.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Want to adjust the stack, or shall I proceed with Option A?","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Message actions","depth":24,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"ok sounds good. Implement all you suggested","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":23,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Thinking","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Starting implementation. Let me first read all the reference files I'll need to copy from.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"parser.js","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"parser.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"payments.js","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"payments.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":",","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"index.js","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"index.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"App.jsx","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"App.jsx","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"FilterBar.jsx","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"FilterBar.jsx","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"PaymentTable.jsx","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"PaymentTable.jsx","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":23,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Thinking","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Now let me read the remaining frontend files and the Dockerfile from payments-logger.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"main.jsx","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"main.jsx","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"index.css","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"index.css","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"package.json","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"package.json","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Dockerfile","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Dockerfile","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Dockerfile","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Dockerfile","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"vite.config.js","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"vite.config.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"tailwind.config.js","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"tailwind.config.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"postcss.config.js","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"postcss.config.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":23,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Thinking","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"index.html","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"index.html","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"dskuploader.py","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"dskuploader.py","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":23,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Thinking","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Let me also grab the remaining frontend components.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"PaymentCard.jsx","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"PaymentCard.jsx","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"PaymentList.jsx","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"PaymentList.jsx","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"schema.prisma","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"schema.prisma","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":23,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Thinking","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Good, I have everything I need. Let me set up the todo list and start building.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":23,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Thinking","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Update Todos","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Create folder structure and root config files","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write backend Prisma schema and migration","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write backend package.json and Dockerfile","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write backend src files (auth, parser, csvParser, index)","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write backend routes (payments.js, upload.js)","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write frontend config files","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write frontend React components","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Build and verify with docker compose","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Create finance-hub directory structure","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"mkdir -p /volume2/docker/finance/finance-hub/backend/src/routes \\\n /volume2/docker/finance/finance-hub/backend/prisma/migrations/20260508_init \\\n /volume2/docker/finance/finance-hub/frontend/src/components && echo \"done\"","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"done","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"docker-compose.yml","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"docker-compose.yml","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"45 lines","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"version: '3.8'\n\nservices:\n db:\n image: postgres:16-alpine\n restart: unless-stopped\n environment:\n POSTGRES_USER: finance\n POSTGRES_PASSWORD: ${DB_PASSWORD}\n POSTGRES_DB: finance_hub\n volumes:\n - pgdata:/var/lib/postgresql/data\n healthcheck:\n test: [\"CMD-SHELL\", \"pg_isready -U finance -d finance_hub\"]\n interval: 5s\n timeout: 5s\n retries: 5\n\n backend:\n build: ./backend\n restart: unless-stopped\n environment:\n DATABASE_URL: postgresql://finance:${DB_PASSWORD}@db:5432/finance_hub\n PORT: \"3001\"\n NOTIFIER_URL: ${NOTIFIER_URL}\n NOTIFIER_CHANNEL: ${NOTIFIER_CHANNEL:-viber}\n NOTIFY_DEFAULT_PHONE: ${NOTIFY_DEFAULT_PHONE}\n TZ: ${TZ:-Europe/Sofia}\n ports:\n - \"${BACKEND_PORT:-3001}:3001\"\n depends_on:\n db:\n condition: service_healthy\n\n frontend:\n build: ./frontend\n restart: unless-stopped\n ports:\n - \"${FRONTEND_PORT:-5175}:5173\"\n depends_on:\n - backend\n\nvolumes:\n pgdata:","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":".env.example","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":".env.example","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"15 lines","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"# Database\nDB_PASSWORD=change_me_strong_password\n\n# Notifier service (for SMS payment notifications)\nNOTIFIER_URL=https://notifier.lakylak.xyz\nNOTIFIER_CHANNEL=viber\nNOTIFY_DEFAULT_PHONE=+359000000000\n\n# Timezone (used by SMS parser for Bulgarian bank timestamps)\nTZ=Europe/Sofia\n\n# Ports (optional — defaults shown)\nBACKEND_PORT=3001\nFRONTEND_PORT=5175","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":".gitignore","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":".gitignore","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"5 lines","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".env\nnode_modules/\ndist/\n*.log","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Update Todos","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Create folder structure and root config files","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write backend Prisma schema and migration","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write backend package.json and Dockerfile","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write backend src files (auth, parser, csvParser, index)","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write backend routes (payments.js, upload.js)","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write frontend config files","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write frontend React components","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Build and verify with docker compose","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"schema.prisma","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"schema.prisma","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"54 lines","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"generator client {\n provider = \"prisma-client-js\"\n}\n\ndatasource db {\n provider = \"postgresql\"\n url = env(\"DATABASE_URL\")\n}\n\nmodel Payment {\n id Int @id @default(autoincrement())\n rawMessage String @map(\"raw_message\")\n date DateTime?\n type String?\n card String?\n recipient String?\n amount Float?\n currency String? @default(\"EUR\")\n balance Float?\n source Source @default(INGEST)\n status Status @default(UNPROCESSED)\n tags Tag[]\n notifiedAt DateTime? @map(\"notified_at\")\n notifyPhone String? @map(\"notify_phone\")\n debitBgn Float? @map(\"debit_bgn\")\n creditBgn Float? @map(\"credit_bgn\")\n transactionType String? @map(\"transaction_type\")\n payerAccount String? @map(\"payer_account\")\n createdAt DateTime @default(now()) @map(\"created_at\")\n updatedAt DateTime @updatedAt @map(\"updated_at\")\n\n @@map(\"payments\")\n}\n\nmodel Tag {\n id Int @id @default(autoincrement())\n name String @unique\n color String @default(\"#6b7280\")\n payments Payment[]\n\n @@map(\"tags\")\n}\n\nenum Status {\n UNPROCESSED\n SENT\n SKIPPED\n}\n\nenum Source {\n INGEST\n UPLOAD\n}","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"migration.sql","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"migration.sql","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"55 lines","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"-- CreateEnum\nCREATE TYPE \"Status\" AS ENUM ('UNPROCESSED', 'SENT', 'SKIPPED');\nCREATE TYPE \"Source\" AS ENUM ('INGEST', 'UPLOAD');\n\n-- CreateTable\nCREATE TABLE \"payments\" (\n \"id\" SERIAL PRIMARY KEY,\n \"raw_message\" TEXT NOT NULL,\n \"date\" TIMESTAMP(3),\n \"type\" TEXT,\n \"card\" TEXT,\n \"recipient\" TEXT,\n \"amount\" DOUBLE PRECISION,\n \"currency\" TEXT DEFAULT 'EUR',\n \"balance\" DOUBLE PRECISION,\n \"source\" \"Source\" NOT NULL DEFAULT 'INGEST',\n \"status\" \"Status\" NOT NULL DEFAULT 'UNPROCESSED',\n \"notified_at\" TIMESTAMP(3),\n \"notify_phone\" TEXT,\n \"debit_bgn\" DOUBLE PRECISION,\n \"credit_bgn\" DOUBLE PRECISION,\n \"transaction_type\" TEXT,\n \"payer_account\" TEXT,\n \"created_at\" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,\n \"updated_at\" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP\n);\n\n-- CreateTable\nCREATE TABLE \"tags\" (\n \"id\" SERIAL PRIMARY KEY,\n \"name\" TEXT NOT NULL,\n \"color\" TEXT NOT NULL DEFAULT '#6b7280'\n);\n\n-- CreateUniqueIndex\nCREATE UNIQUE INDEX \"tags_name_key\" ON \"tags\"(\"name\");\n\n-- CreateTable (M2M join)\nCREATE TABLE \"_PaymentToTag\" (\n \"A\" INTEGER NOT NULL,\n \"B\" INTEGER NOT NULL,\n CONSTRAINT \"_PaymentToTag_AB_pkey\" PRIMARY KEY (\"A\", \"B\")\n);\n\nCREATE INDEX \"_PaymentToTag_B_index\" ON \"_PaymentToTag\"(\"B\");\n\n-- AddForeignKey\nALTER TABLE \"_PaymentToTag\"\n ADD CONSTRAINT \"_PaymentToTag_A_fkey\"\n FOREIGN KEY (\"A\") REFERENCES \"payments\"(\"id\") ON DELETE CASCADE ON UPDATE CASCADE;\n\nALTER TABLE \"_PaymentToTag\"\n ADD CONSTRAINT \"_PaymentToTag_B_fkey\"\n FOREIGN KEY (\"B\") REFERENCES \"tags\"(\"id\") ON DELETE CASCADE ON UPDATE CASCADE;","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"migration_lock.toml","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"migration_lock.toml","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"4 lines","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"# Please do not edit this file manually\n# It should be added in your version-control system (e.g., Git)\nprovider = \"postgresql\"","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Update Todos","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Create folder structure and root config files","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write backend Prisma schema and migration","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write backend package.json and Dockerfile","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write backend src files (auth, parser, csvParser, index)","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write backend routes (payments.js, upload.js)","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write frontend config files","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write frontend React components","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Build and verify with docker compose","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"package.json","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"package.json","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"26 lines","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"{\n \"name\": \"finance-hub-backend\",\n \"version\": \"1.0.0\",\n \"main\": \"src/index.js\",\n \"scripts\": {\n \"start\": \"node src/index.js\",\n \"dev\": \"nodemon src/index.js\",\n \"prisma:generate\": \"prisma generate\",\n \"prisma:migrate\": \"prisma migrate deploy\"\n },\n \"dependencies\": {\n \"@prisma/client\": \"^5.22.0\",\n \"cors\": \"^2.8.5\",\n \"csv-parse\": \"^5.5.6\",\n \"express\": \"^4.21.1\",\n \"express-rate-limit\": \"^7.4.0\",\n \"iconv-lite\": \"^0.6.3\",\n \"morgan\": \"^1.10.0\",\n \"multer\": \"^1.4.5-lts.1\"\n },\n \"devDependencies\": {\n \"nodemon\": \"^3.1.7\",\n \"prisma\": \"^5.22.0\"\n }\n}","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Dockerfile","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Dockerfile","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"18 lines","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FROM node:20-alpine\n\nRUN apk add --no-cache openssl\n\nWORKDIR /app\n\nCOPY package.json package-lock.json* ./\nRUN npm install\n\nCOPY prisma ./prisma\nRUN npx prisma generate\n\nCOPY src ./src\n\nEXPOSE 3001\n\nCMD [\"sh\", \"-c\", \"npx prisma migrate deploy && node src/index.js\"]","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Update Todos","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Create folder structure and root config files","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write backend Prisma schema and migration","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write backend package.json and Dockerfile","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write backend src files (auth, parser, csvParser, index)","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write backend routes (payments.js, upload.js)","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write frontend config files","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write frontend React components","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Build and verify with docker compose","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"auth.js","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"auth.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"27 lines","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"const PUBLIC_PATHS = new Set([\n '/api/health',\n '/api/payments/ingest',\n]);\n\nfunction authentikMiddleware(req, res, next) {\n if (PUBLIC_PATHS.has(req.path)) return next();\n\n const username = req.headers['x-authentik-username'];\n if (!username) {\n return res.status(401).json({ error: 'Unauthorized — missing Authentik session' });\n }\n\n req.user = {\n username,\n email: req.headers['x-authentik-email'] || null,\n groups: (req.headers['x-authentik-groups'] || '')\n .split(',')\n .map(g => g.trim())\n .filter(Boolean),\n };\n\n next();\n}\n\nmodule.exports = { authentikMiddleware };","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"parser.js","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"parser.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"104 lines","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/**\n * Parses SMS payment messages from Bulgarian banks (DSK Bank, etc.)\n *\n * Supported formats:\n *\n * POS / INTERNET / ECOM / P2P payment:\n * DSK Bank. Na DD/MM/YYYY v HH:MM sa plateni AMOUNT CURRENCY s karta CARD na POS s adres: RECIPIENT. Nalichni: BALANCE CURRENCY.\n *\n * ATM withdrawal:\n * DSK Bank. Na DD/MM/YYYY v HH:MM sa iztegleni AMOUNT CURRENCY s karta CARD ot ATM s adres: RECIPIENT. Nalichni: BALANCE CURRENCY.\n *\n * ATM utility payment (amount may include fee as AMOUNT/FEE):\n * DSK Bank. Na DD/MM/YYYY v HH:MM sa plateni AMOUNT CURRENCY/FEE CURRENCY s karta CARD na ATM s adres:RECIPIENT. Nalichni: BALANCE CURRENCY.\n */\n\nconst LOCAL_TZ = process.env.TZ || 'Europe/Sofia';\n\n/**\n * Convert a local-timezone date/time to a UTC Date object.\n * Uses Intl to resolve the actual UTC offset (DST-aware).\n */\nfunction localToUtc(year, month, day, hour, minute) {\n const naive = new Date(Date.UTC(year, month - 1, day, hour, minute, 0));\n\n const formatter = new Intl.DateTimeFormat('en-US', {\n timeZone: LOCAL_TZ,\n year: 'numeric', month: '2-digit', day: '2-digit',\n hour: '2-digit', minute: '2-digit', second: '2-digit',\n hour12: false,\n });\n\n const parts = {};\n formatter.formatToParts(naive).forEach(p => { parts[p.type] = p.value; });\n\n const localAtNaive = new Date(Date.UTC(\n parseInt(parts.year), parseInt(parts.month) - 1, parseInt(parts.day),\n parseInt(parts.hour) % 24, parseInt(parts.minute), parseInt(parts.second),\n ));\n\n const offsetMs = localAtNaive.getTime() - naive.getTime();\n return new Date(Date.UTC(year, month - 1, day, hour, minute, 0) - offsetMs);\n}\n\nfunction parsePaymentSms(message) {\n const result = {\n rawMessage: message,\n date: null,\n type: null,\n card: null,\n recipient: null,\n amount: null,\n balance: null,\n };\n\n // Date and time: \"Na DD/MM/YYYY v HH:MM\"\n const dateMatch = message.match(/Na (\\d{2})\\/(\\d{2})\\/(\\d{4}) v (\\d{2}):(\\d{2})/i);\n if (dateMatch) {\n const [, day, month, year, hour, minute] = dateMatch;\n result.date = localToUtc(\n parseInt(year), parseInt(month), parseInt(day),\n parseInt(hour), parseInt(minute),\n );\n }\n\n // Card mask: \"s karta 400915***4447\" or \"s karta 483890***7162\"\n const cardMatch = message.match(/s karta\\s+([\\d*]+)/i);\n if (cardMatch) {\n result.card = cardMatch[1];\n }\n\n // Transaction type: supports both prepositions\n // \"na POS\" / \"na ATM\" / \"na INTERNET\" etc. (payment)\n // \"ot ATM\" (withdrawal)\n const typeMatch = message.match(/(?:na|ot)\\s+(POS|ATM|INTERNET|ECOM|P2P)\\b/i);\n if (typeMatch) {\n result.type = typeMatch[1].toUpperCase();\n }\n\n // Recipient address: \"s adres: MERCHANT\" or \"s adres:MERCHANT\" (no space variant)\n const recipientMatch = message.match(/s adres:\\s*([^.]+)\\./i);\n if (recipientMatch) {\n result.recipient = recipientMatch[1].trim();\n }\n\n // Amount: handles both verbs and the AMOUNT/FEE suffix format\n // \"sa plateni 7.78 EUR\"\n // \"sa iztegleni 400.00 EUR\"\n // \"sa plateni 0.50 EUR/0.50 EUR\" → captures 0.50 (the charged amount, ignoring fee)\n const amountMatch = message.match(/sa (?:plateni|iztegleni)\\s+([\\d.,]+)\\s+[A-Z]{3}/i);\n if (amountMatch) {\n result.amount = parseFloat(amountMatch[1].replace(',', '.'));\n }\n\n // Balance: \"Nalichni: 2583.07 EUR.\"\n const balanceMatch = message.match(/Nalichni:\\s*([\\d.,]+)\\s+[A-Z]{3}/i);\n if (balanceMatch) {\n result.balance = parseFloat(balanceMatch[1].replace(',', '.'));\n }\n\n return result;\n}\n\nmodule.exports = { parsePaymentSms };","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"csvParser.js","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"csvParser.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"175 lines","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/**\n * DSK Bank CSV parser — Node.js port of dskuploader.py\n *\n * DSK Bank exports use Windows-1251 (cp1251) encoding.\n * Each row maps to a Payment record with source=UPLOAD, currency=BGN.\n */\n\nconst { parse } = require('csv-parse');\nconst iconv = require('iconv-lite');\n\nconst SKIP_TYPE = 'ТРАНСФЕР СОБСТВЕНИ СМЕТКИ';\nconst CARD_REGEX = /^\\d{6}x{6}\\d{4}$/;\nconst POS_REGEX = /^\\s*ПЛАЩАНЕ\\s+НА\\s+ПОС\\s+\\d{2}\\.\\d{2}\\.\\d{4}\\s+\\d{2}:\\d{2}/;\n\nconst COL = {\n DATE: 'Дата',\n TYPE: 'Вид на трансакцията',\n REASON: 'Основание',\n DEBIT: 'Дебит BGN',\n CREDIT: 'Кредит BGN',\n PAYEE: 'Наредител/Получател',\n ACCT: 'Номер сметка на наредителя / получателя',\n};\n\nconst TAG_RULES = [\n ['reason', 'ЗАПЛАТА', 'Salary'],\n ['reason', 'ТЕГЛЕНЕ НА ATM', 'ATM'],\n ['reason', 'ПЛАЩАНЕ ПО ЗАЕМ', 'Home Credit'],\n ['reason', 'АВТ.ТАКСА ОБСЛУЖВАНЕ', 'Bills'],\n ['transactionType', 'КОМУНАЛНИ УСЛУГИ', 'Bills'],\n ['payee', 'VIVACOM', 'Subscriptions'],\n ['payee', 'Google', 'Subscriptions'],\n ['payee', 'SkyShowtime', 'Subscriptions'],\n ['payee', 'NETFLIX', 'Subscriptions'],\n ['payee', 'LUKOIL', 'Bills'],\n ['payee', 'CityGate', 'Bills'],\n ['payee', 'CBA', 'Groceries'],\n ['payee', 'FANTASTICO', 'Groceries'],\n ['payee', 'LIDL', 'Groceries'],\n];\n\nfunction parseNum(val) {\n if (val == null || val === '') return null;\n if (typeof val === 'number') return isNaN(val) ? null : val;\n const s = String(val).trim().replace(/\\xa0/g, '').replace(/ /g, '').replace(',', '.');\n const n = parseFloat(s);\n return isNaN(n) ? null : n;\n}\n\nfunction parseDate(val) {\n if (!val) return null;\n const s = String(val).trim();\n const m = s.match(/^(\\d{2})\\.(\\d{2})\\.(\\d{4})$/);\n if (m) {\n return new Date(Date.UTC(parseInt(m[3]), parseInt(m[2]) - 1, parseInt(m[1])));\n }\n return null;\n}\n\nfunction processReasonAndCard(reason) {\n if (!reason || typeof reason !== 'string') return { reason: '', card: null };\n\n const parts = reason.trim().split(' ');\n let card = null;\n let cleanReason = reason.trim();\n\n if (parts[0] && CARD_REGEX.test(parts[0])) {\n card = parts[0];\n cleanReason = parts.slice(1).join(' ').trim();\n }\n\n if (POS_REGEX.test(cleanReason)) {\n const posParts = cleanReason.split('<br/>');\n try {\n const dateTime = posParts[0].split('ПОС ')[1];\n cleanReason = `POS PAYMENT ${dateTime}`;\n } catch (_) { /* keep original */ }\n }\n\n return { reason: cleanReason.replace(/\\s+/g, ' ').trim(), card };\n}\n\nfunction generateTags(fields) {\n const tags = new Set();\n for (const [field, keyword, tagName] of TAG_RULES) {\n if ((fields[field] || '').includes(keyword)) {\n tags.add(tagName);\n }\n }\n return Array.from(tags);\n}\n\nfunction processRow(row) {\n const transactionType = (row[COL.TYPE] || '').trim();\n if (transactionType === SKIP_TYPE) return null;\n\n const { reason, card } = processReasonAndCard(row[COL.REASON]);\n const payee = (row[COL.PAYEE] || '').trim();\n const payerAccount = (row[COL.ACCT] || '').trim();\n const debitBgn = parseNum(row[COL.DEBIT]);\n const creditBgn = parseNum(row[COL.CREDIT]);\n const date = parseDate(row[COL.DATE]);\n\n const autoTags = generateTags({ reason, transactionType, payee, debitBgn, creditBgn });\n\n const amount = debitBgn ?? creditBgn ?? null;\n\n const rawMessage = [\n row[COL.DATE] && `Date: ${row[COL.DATE]}`,\n transactionType && `Type: ${transactionType}`,\n payee && `Payee: ${payee}`,\n debitBgn != null && `Debit: ${debitBgn} BGN`,\n creditBgn != null && `Credit: ${creditBgn} BGN`,\n ].filter(Boolean).join(' | ');\n\n return {\n rawMessage,\n date,\n type: null,\n card,\n recipient: payee || null,\n amount,\n currency: 'BGN',\n balance: null,\n source: 'UPLOAD',\n debitBgn,\n creditBgn,\n transactionType: transactionType || null,\n payerAccount: payerAccount || null,\n autoTags,\n };\n}\n\n/**\n * Parse a Buffer containing a DSK Bank CSV (cp1251 or UTF-8).\n * Returns { rows, skipped, errors }.\n */\nasync function parseDskCsv(buffer) {\n // Try cp1251 first (DSK Bank export encoding), fall back to UTF-8\n let text = iconv.decode(buffer, 'cp1251');\n if (!text.includes(COL.DATE)) {\n text = buffer.toString('utf-8');\n }\n\n return new Promise((resolve, reject) => {\n const rows = [];\n const errors = [];\n let skipped = 0;\n\n const parser = parse(text, {\n columns: true,\n skip_empty_lines: true,\n trim: true,\n relax_column_count: true,\n });\n\n parser.on('readable', () => {\n let record;\n while ((record = parser.read()) !== null) {\n try {\n const row = processRow(record);\n if (row === null) { skipped++; } else { rows.push(row); }\n } catch (err) {\n errors.push(err.message);\n }\n }\n });\n\n parser.on('error', reject);\n parser.on('end', () => resolve({ rows, skipped, errors }));\n });\n}\n\nmodule.exports = { parseDskCsv };","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"index.js","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"index.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"39 lines","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"const express = require('express');\nconst cors = require('cors');\nconst morgan = require('morgan');\nconst rateLimit = require('express-rate-limit');\nconst { authentikMiddleware } = require('./auth');\nconst paymentsRouter = require('./routes/payments');\nconst uploadRouter = require('./routes/upload');\n\nconst app = express();\nconst PORT = process.env.PORT || 3001;\n\napp.use(cors());\napp.use(express.json({ limit: '16kb' }));\napp.use(morgan('combined'));\n\n// Rate-limit the public ingest endpoint before auth middleware\nconst ingestLimiter = rateLimit({\n windowMs: 60 * 1000,\n max: 200,\n standardHeaders: true,\n legacyHeaders: false,\n message: { error: 'Too many requests, slow down' },\n});\napp.use('/api/payments/ingest', ingestLimiter);\n\n// Authentik header auth (skips /api/health and /api/payments/ingest)\napp.use(authentikMiddleware);\n\napp.get('/api/health', (_req, res) => {\n res.json({ status: 'ok', timestamp: new Date().toISOString() });\n});\n\napp.use('/api/payments', paymentsRouter);\napp.use('/api/upload', uploadRouter);\n\napp.listen(PORT, '0.0.0.0', () => {\n console.log(`Finance Hub API running on port ${PORT}`);\n});","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Update Todos","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Create folder structure and root config files","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write backend Prisma schema and migration","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write backend package.json and Dockerfile","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write backend src files (auth, parser, csvParser, index)","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write backend routes (payments.js, upload.js)","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write frontend config files","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write frontend React components","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Build and verify with docker compose","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"payments.js","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"payments.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"399 lines","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"const express = require('express');\nconst { PrismaClient } = require('@prisma/client');\nconst { parsePaymentSms } = require('../parser');\n\nconst router = express.Router();\nconst prisma = new PrismaClient();\n\nconst NOTIFIER_URL = process.env.NOTIFIER_URL;\nconst NOTIFIER_CHANNEL = process.env.NOTIFIER_CHANNEL || 'viber';\nconst DEFAULT_PHONE = process.env.NOTIFY_DEFAULT_PHONE;\n\n// ── Helpers ───────────────────────────────────────────────────────────────────\n\nfunction parseId(raw) {\n const id = parseInt(raw, 10);\n return Number.isFinite(id) ? id : null;\n}\n\nfunction formatNotifyMessage(payment) {\n const currency = payment.currency || 'EUR';\n const parts = [];\n if (payment.amount != null) parts.push(`Amount: ${payment.amount.toFixed(2)} ${currency}`);\n if (payment.recipient) parts.push(`At: ${payment.recipient}`);\n if (payment.balance != null) parts.push(`Balance: ${payment.balance.toFixed(2)} ${currency}`);\n if (payment.date) parts.push(`Date: ${new Date(payment.date).toLocaleString('en-GB')}`);\n return parts.join('\\n');\n}\n\nasync function sendNotification(payment) {\n if (!NOTIFIER_URL) {\n console.warn('[NOTIFY] NOTIFIER_URL not set — skipping notification');\n return;\n }\n\n const phone = payment.notifyPhone || DEFAULT_PHONE;\n if (!phone) {\n console.warn('[NOTIFY] No phone number for payment #' + payment.id + ' and NOTIFY_DEFAULT_PHONE not set');\n return;\n }\n\n const body = {\n phone,\n notification: NOTIFIER_CHANNEL,\n message: formatNotifyMessage(payment),\n };\n\n const res = await fetch(NOTIFIER_URL, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n });\n\n if (!res.ok) {\n const text = await res.text().catch(() => '');\n throw new Error(`Notifier responded ${res.status}: ${text}`);\n }\n}\n\n// ── Ingest a payment (public — no auth) ──────────────────────────────────────\n//\n// Two modes:\n//\n// SMS mode (default):\n// { \"message\": \"<raw SMS text>\", \"notifyPhone\": \"...\" }\n//\n// Structured mode (Apple Wallet / manual):\n// { \"ingestMode\": \"apple_wallet\", \"amount\": 7.78, \"recipient\": \"Apple Store\",\n// \"type\": \"WALLET\", \"card\": \"••••4447\", \"date\": \"2026-02-22T10:30:00Z\" }\n//\nrouter.post('/ingest', async (req, res) => {\n try {\n const { message, notifyPhone, ingestMode } = req.body;\n\n let data;\n\n if (ingestMode === 'apple_wallet' || (!message && req.body.amount != null)) {\n // ── Structured / Apple Wallet mode ──────────────────────────────────────\n const { amount, recipient, type, card, date, balance } = req.body;\n if (amount == null || !recipient) {\n return res.status(400).json({ error: 'amount and recipient are required for structured ingest' });\n }\n\n const rawMessage = [\n `Source: ${ingestMode || 'structured'}`,\n `Amount: ${amount}`,\n recipient && `Recipient: ${recipient}`,\n type && `Type: ${type}`,\n card && `Card: ${card}`,\n ].filter(Boolean).join(' | ');\n\n data = {\n rawMessage,\n date: date ? new Date(date) : new Date(),\n type: type || 'WALLET',\n card: card || null,\n recipient,\n amount: parseFloat(amount),\n currency: 'EUR',\n balance: balance != null ? parseFloat(balance) : null,\n source: 'INGEST',\n notifyPhone: notifyPhone || null,\n };\n\n } else {\n // ── SMS mode ─────────────────────────────────────────────────────────────\n if (!message) {\n return res.status(400).json({ error: 'message is required' });\n }\n if (typeof message !== 'string' || message.length > 2000) {\n return res.status(400).json({ error: 'message must be a string under 2000 characters' });\n }\n\n const parsed = parsePaymentSms(message);\n data = {\n rawMessage: parsed.rawMessage,\n date: parsed.date,\n type: parsed.type,\n card: parsed.card,\n recipient: parsed.recipient,\n amount: parsed.amount,\n currency: 'EUR',\n balance: parsed.balance,\n source: 'INGEST',\n notifyPhone: notifyPhone || null,\n };\n }\n\n const payment = await prisma.payment.create({\n data,\n include: { tags: true },\n });\n\n res.status(201).json(payment);\n } catch (err) {\n console.error('Ingest error:', err);\n res.status(500).json({ error: 'Failed to ingest payment' });\n }\n});\n\n// ── List payments with filtering ──────────────────────────────────────────────\nrouter.get('/', async (req, res) => {\n try {\n const {\n status,\n type,\n tag,\n source,\n recipient,\n dateFrom,\n dateTo,\n search,\n sortBy = 'createdAt',\n sortDir = 'desc',\n page = 1,\n } = req.query;\n\n const limit = Math.min(parseInt(req.query.limit, 10) || 50, 200);\n\n const where = {};\n\n if (status) where.status = status;\n if (type) where.type = type;\n if (source) where.source = source;\n if (recipient) where.recipient = { contains: recipient, mode: 'insensitive' };\n if (tag) where.tags = { some: { name: tag } };\n if (search) {\n where.OR = [\n { rawMessage: { contains: search, mode: 'insensitive' } },\n { recipient: { contains: search, mode: 'insensitive' } },\n ];\n }\n if (dateFrom || dateTo) {\n where.date = {};\n if (dateFrom) where.date.gte = new Date(dateFrom);\n if (dateTo) where.date.lte = new Date(dateTo);\n }\n\n const allowedSortFields = ['date', 'amount', 'balance', 'recipient', 'type', 'source', 'createdAt', 'status'];\n const orderField = allowedSortFields.includes(sortBy) ? sortBy : 'createdAt';\n const orderDir = sortDir === 'asc' ? 'asc' : 'desc';\n\n const skip = (parseInt(page, 10) - 1) * limit;\n\n const [payments, total] = await Promise.all([\n prisma.payment.findMany({\n where,\n include: { tags: true },\n orderBy: { [orderField]: orderDir },\n skip,\n take: limit,\n }),\n prisma.payment.count({ where }),\n ]);\n\n res.json({ payments, total, page: parseInt(page, 10), limit });\n } catch (err) {\n console.error('List error:', err);\n res.status(500).json({ error: 'Failed to list payments' });\n }\n});\n\n// ── Get filter options ────────────────────────────────────────────────────────\nrouter.get('/meta/filters', async (_req, res) => {\n try {\n const [types, recipients, tags, sources] = await Promise.all([\n prisma.payment.findMany({ distinct: ['type'], select: { type: true }, where: { type: { not: null } } }),\n prisma.payment.findMany({ distinct: ['recipient'], select: { recipient: true }, where: { recipient: { not: null } } }),\n prisma.tag.findMany({ orderBy: { name: 'asc' } }),\n prisma.payment.findMany({ distinct: ['source'], select: { source: true } }),\n ]);\n\n res.json({\n types: types.map(t => t.type),\n recipients: recipients.map(r => r.recipient),\n tags,\n sources: sources.map(s => s.source),\n });\n } catch (err) {\n res.status(500).json({ error: 'Failed to get filters' });\n }\n});\n\n// ── Get all tags ──────────────────────────────────────────────────────────────\nrouter.get('/meta/tags', async (_req, res) => {\n try {\n const tags = await prisma.tag.findMany({ orderBy: { name: 'asc' } });\n res.json(tags);\n } catch (err) {\n res.status(500).json({ error: 'Failed to list tags' });\n }\n});\n\n// ── Get single payment ────────────────────────────────────────────────────────\nrouter.get('/:id', async (req, res) => {\n const id = parseId(req.params.id);\n if (id === null) return res.status(400).json({ error: 'Invalid id' });\n\n try {\n const payment = await prisma.payment.findUnique({\n where: { id },\n include: { tags: true },\n });\n if (!payment) return res.status(404).json({ error: 'Not found' });\n res.json(payment);\n } catch (err) {\n console.error('Get error:', err);\n res.status(500).json({ error: 'Failed to get payment' });\n }\n});\n\n// ── Update payment metadata (status) ─────────────────────────────────────────\nrouter.patch('/:id', async (req, res) => {\n const id = parseId(req.params.id);\n if (id === null) return res.status(400).json({ error: 'Invalid id' });\n\n try {\n const { status } = req.body;\n const data = {};\n\n if (status) {\n const validStatuses = ['UNPROCESSED', 'SENT', 'SKIPPED'];\n if (!validStatuses.includes(status)) {\n return res.status(400).json({ error: `Invalid status. Must be one of: ${validStatuses.join(', ')}` });\n }\n data.status = status;\n }\n\n if (Object.keys(data).length === 0) {\n return res.status(400).json({ error: 'No valid fields to update' });\n }\n\n const updated = await prisma.payment.update({\n where: { id },\n data,\n include: { tags: true },\n });\n res.json(updated);\n } catch (err) {\n if (err.code === 'P2025') return res.status(404).json({ error: 'Not found' });\n console.error('Update error:', err);\n res.status(500).json({ error: 'Failed to update payment' });\n }\n});\n\n// ── Delete payment ───────────────────────────────────────────────────────────\nrouter.delete('/:id', async (req, res) => {\n const id = parseId(req.params.id);\n if (id === null) return res.status(400).json({ error: 'Invalid id' });\n\n try {\n await prisma.payment.delete({ where: { id } });\n res.json({ success: true });\n } catch (err) {\n if (err.code === 'P2025') return res.status(404).json({ error: 'Not found' });\n console.error('Delete error:', err);\n res.status(500).json({ error: 'Failed to delete payment' });\n }\n});\n\n// ── Send notification (mark as SENT + call notifier service) ─────────────────\nrouter.post('/:id/send', async (req, res) => {\n const id = parseId(req.params.id);\n if (id === null) return res.status(400).json({ error: 'Invalid id' });\n\n try {\n const payment = await prisma.payment.findUnique({ where: { id } });\n if (!payment) return res.status(404).json({ error: 'Not found' });\n if (payment.status !== 'UNPROCESSED') {\n return res.status(409).json({ error: `Payment is already ${payment.status.toLowerCase()}` });\n }\n\n await sendNotification(payment);\n\n const updated = await prisma.payment.update({\n where: { id },\n data: { status: 'SENT', notifiedAt: new Date() },\n include: { tags: true },\n });\n\n res.json(updated);\n } catch (err) {\n console.error('Send error:', err);\n res.status(500).json({ error: 'Failed to send notification' });\n }\n});\n\n// ── Skip notification (mark as SKIPPED) ──────────────────────────────────────\nrouter.post('/:id/skip', async (req, res) => {\n const id = parseId(req.params.id);\n if (id === null) return res.status(400).json({ error: 'Invalid id' });\n\n try {\n const payment = await prisma.payment.findUnique({ where: { id } });\n if (!payment) return res.status(404).json({ error: 'Not found' });\n if (payment.status !== 'UNPROCESSED') {\n return res.status(409).json({ error: `Payment is already ${payment.status.toLowerCase()}` });\n }\n\n const updated = await prisma.payment.update({\n where: { id },\n data: { status: 'SKIPPED' },\n include: { tags: true },\n });\n res.json(updated);\n } catch (err) {\n console.error('Skip error:', err);\n res.status(500).json({ error: 'Failed to skip payment' });\n }\n});\n\n// ── Add tag to payment ────────────────────────────────────────────────────────\nrouter.post('/:id/tags', async (req, res) => {\n const id = parseId(req.params.id);\n if (id === null) return res.status(400).json({ error: 'Invalid id' });\n\n try {\n const { name, color } = req.body;\n if (!name) return res.status(400).json({ error: 'tag name is required' });\n\n const tag = await prisma.tag.upsert({\n where: { name },\n update: {},\n create: { name, color: color || '#6b7280' },\n });\n\n const updated = await prisma.payment.update({\n where: { id },\n data: { tags: { connect: { id: tag.id } } },\n include: { tags: true },\n });\n\n res.json(updated);\n } catch (err) {\n console.error('Tag error:', err);\n res.status(500).json({ error: 'Failed to add tag' });\n }\n});\n\n// ── Remove tag from payment ───────────────────────────────────────────────────\nrouter.delete('/:id/tags/:tagId', async (req, res) => {\n const id = parseId(req.params.id);\n const tagId = parseId(req.params.tagId);\n if (id === null || tagId === null) return res.status(400).json({ error: 'Invalid id' });\n\n try {\n const updated = await prisma.payment.update({\n where: { id },\n data: { tags: { disconnect: { id: tagId } } },\n include: { tags: true },\n });\n res.json(updated);\n } catch (err) {\n console.error('Remove tag error:', err);\n res.status(500).json({ error: 'Failed to remove tag' });\n }\n});\n\nmodule.exports = router;","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"upload.js","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"upload.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"89 lines","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"const express = require('express');\nconst multer = require('multer');\nconst { PrismaClient } = require('@prisma/client');\nconst { parseDskCsv } = require('../csvParser');\n\nconst router = express.Router();\nconst prisma = new PrismaClient();\n\nconst upload = multer({\n storage: multer.memoryStorage(),\n limits: { fileSize: 10 * 1024 * 1024, files: 10 },\n fileFilter: (_req, file, cb) => {\n if (file.mimetype === 'text/csv' || file.originalname.toLowerCase().endsWith('.csv')) {\n cb(null, true);\n } else {\n cb(new Error('Only CSV files are accepted'));\n }\n },\n});\n\n// POST /api/upload/csv\n// Accepts 1-10 CSV files, parses them, stores to DB with source=UPLOAD.\n// Returns { imported, skipped, errors, payments[] }\nrouter.post('/csv', upload.array('files', 10), async (req, res) => {\n if (!req.files || req.files.length === 0) {\n return res.status(400).json({ error: 'No files uploaded' });\n }\n\n const allRows = [];\n const allErrors = [];\n let totalSkipped = 0;\n\n for (const file of req.files) {\n try {\n const { rows, skipped, errors } = await parseDskCsv(file.buffer);\n allRows.push(...rows);\n totalSkipped += skipped;\n allErrors.push(...errors.map(e => `${file.originalname}: ${e}`));\n } catch (err) {\n allErrors.push(`${file.originalname}: ${err.message}`);\n }\n }\n\n if (allRows.length === 0) {\n return res.status(422).json({\n error: 'No importable rows found',\n skipped: totalSkipped,\n errors: allErrors,\n });\n }\n\n const created = [];\n\n for (const row of allRows) {\n const { autoTags, ...paymentData } = row;\n try {\n const tagConnects = [];\n for (const tagName of autoTags) {\n const tag = await prisma.tag.upsert({\n where: { name: tagName },\n update: {},\n create: { name: tagName, color: '#6b7280' },\n });\n tagConnects.push({ id: tag.id });\n }\n\n const payment = await prisma.payment.create({\n data: {\n ...paymentData,\n ...(tagConnects.length ? { tags: { connect: tagConnects } } : {}),\n },\n include: { tags: true },\n });\n created.push(payment);\n } catch (err) {\n allErrors.push(`Row insert failed: ${err.message}`);\n }\n }\n\n res.status(201).json({\n imported: created.length,\n skipped: totalSkipped,\n errors: allErrors,\n payments: created,\n });\n});\n\nmodule.exports = router;","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Update Todos","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Create folder structure and root config files","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write backend Prisma schema and migration","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write backend package.json and Dockerfile","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write backend src files (auth, parser, csvParser, index)","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write backend routes (payments.js, upload.js)","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write frontend config files","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write frontend React components","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Build and verify with docker compose","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Now writing all frontend config files:","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"package.json","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"package.json","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"24 lines","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"{\n \"name\": \"finance-hub-frontend\",\n \"version\": \"1.0.0\",\n \"type\": \"module\",\n \"scripts\": {\n \"dev\": \"vite\",\n \"build\": \"vite build\",\n \"preview\": \"vite preview\"\n },\n \"dependencies\": {\n \"lucide-react\": \"^0.460.0\",\n \"react\": \"^18.3.1\",\n \"react-dom\": \"^18.3.1\"\n },\n \"devDependencies\": {\n \"@types/react\": \"^18.3.12\",\n \"@vitejs/plugin-react\": \"^4.3.4\",\n \"autoprefixer\": \"^10.4.20\",\n \"postcss\": \"^8.4.49\",\n \"tailwindcss\": \"^3.4.15\",\n \"vite\": \"^6.0.1\"\n }\n}","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Dockerfile","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Dockerfile","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"13 lines","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FROM node:20-alpine\n\nWORKDIR /app\n\nCOPY package.json package-lock.json* ./\nRUN npm install\n\nCOPY . .\n\nEXPOSE 5173\n\nCMD [\"npm\", \"run\", \"dev\"]","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"vite.config.js","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"vite.config.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"18 lines","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"import { defineConfig } from 'vite';\nimport react from '@vitejs/plugin-react';\n\nexport default defineConfig({\n plugins: [react()],\n server: {\n host: '0.0.0.0',\n port: 5173,\n allowedHosts: ['finance-hub.lakylak.xyz'],\n proxy: {\n '/api': {\n target: 'http://backend:3001',\n changeOrigin: true,\n },\n },\n },\n});","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"tailwind.config.js","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"tailwind.config.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"12 lines","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/** @type {import('tailwindcss').Config} */\nexport default {\n content: [\n \"./index.html\",\n \"./src/**/*.{js,ts,jsx,tsx}\",\n ],\n theme: {\n extend: {},\n },\n plugins: [],\n};","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"postcss.config.js","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"postcss.config.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"7 lines","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"export default {\n plugins: {\n tailwindcss: {},\n autoprefixer: {},\n },\n};","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"index.html","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"index.html","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"14 lines","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <title>Finance Hub</title>\n <link rel=\"icon\" type=\"image/svg+xml\" href=\"data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>💰</text></svg>\" />\n </head>\n <body class=\"bg-gray-50 min-h-screen\">\n <div id=\"root\"></div>\n <script type=\"module\" src=\"/src/main.jsx\"></script>\n </body>\n</html>","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"index.css","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"index.css","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"4 lines","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"@tailwind base;\n@tailwind components;\n@tailwind utilities;","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Update Todos","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Create folder structure and root config files","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write backend Prisma schema and migration","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write backend package.json and Dockerfile","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write backend src files (auth, parser, csvParser, index)","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write backend routes (payments.js, upload.js)","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write frontend config files","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write frontend React components","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Build and verify with docker compose","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Now writing all React components:","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"main.jsx","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"main.jsx","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"11 lines","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"import React from 'react';\nimport ReactDOM from 'react-dom/client';\nimport App from './App';\nimport './index.css';\n\nReactDOM.createRoot(document.getElementById('root')).render(\n <React.StrictMode>\n <App />\n </React.StrictMode>\n);","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"App.jsx","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"App.jsx","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"257 lines","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"import React, { useState, useEffect, useCallback } from 'react';\nimport { LayoutDashboard, Upload, RefreshCw, LogOut } from 'lucide-react';\nimport FilterBar from './components/FilterBar';\nimport PaymentTable from './components/PaymentTable';\nimport UploadPanel from './components/UploadPanel';\n\nconst API_BASE = '/api/payments';\n\nexport default function App() {\n const [activeTab, setActiveTab] = useState('payments');\n const [payments, setPayments] = useState([]);\n const [total, setTotal] = useState(0);\n const [page, setPage] = useState(1);\n const [filters, setFilters] = useState({});\n const [sortBy, setSortBy] = useState('createdAt');\n const [sortDir, setSortDir] = useState('desc');\n const [filterOptions, setFilterOptions] = useState({ types: [], recipients: [], tags: [], sources: [] });\n const [loading, setLoading] = useState(false);\n\n const fetchPayments = useCallback(async () => {\n setLoading(true);\n try {\n const params = new URLSearchParams();\n params.set('page', page);\n params.set('limit', 50);\n params.set('sortBy', sortBy);\n params.set('sortDir', sortDir);\n Object.entries(filters).forEach(([key, val]) => {\n if (val) params.set(key, val);\n });\n const res = await fetch(`${API_BASE}?${params}`);\n const data = await res.json();\n setPayments(data.payments || []);\n setTotal(data.total || 0);\n } catch (err) {\n console.error('Failed to fetch payments:', err);\n } finally {\n setLoading(false);\n }\n }, [page, filters, sortBy, sortDir]);\n\n const fetchFilterOptions = useCallback(async () => {\n try {\n const res = await fetch(`${API_BASE}/meta/filters`);\n const data = await res.json();\n setFilterOptions(data);\n } catch (err) {\n console.error('Failed to fetch filter options:', err);\n }\n }, []);\n\n useEffect(() => {\n fetchPayments();\n }, [fetchPayments]);\n\n useEffect(() => {\n fetchFilterOptions();\n }, [fetchFilterOptions]);\n\n // Refresh payments list after a successful CSV upload\n const handleUploadSuccess = () => {\n fetchPayments();\n fetchFilterOptions();\n setActiveTab('payments');\n };\n\n const handleAction = async (id, action) => {\n try {\n await fetch(`${API_BASE}/${id}/${action}`, { method: 'POST' });\n fetchPayments();\n fetchFilterOptions();\n } catch (err) {\n console.error(`Failed to ${action} payment:`, err);\n }\n };\n\n const handleAddTag = async (id, tagName, tagColor) => {\n try {\n await fetch(`${API_BASE}/${id}/tags`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ name: tagName, color: tagColor }),\n });\n fetchPayments();\n fetchFilterOptions();\n } catch (err) {\n console.error('Failed to add tag:', err);\n }\n };\n\n const handleRemoveTag = async (paymentId, tagId) => {\n try {\n await fetch(`${API_BASE}/${paymentId}/tags/${tagId}`, { method: 'DELETE' });\n fetchPayments();\n } catch (err) {\n console.error('Failed to remove tag:', err);\n }\n };\n\n const handleDelete = async (id) => {\n try {\n await fetch(`${API_BASE}/${id}`, { method: 'DELETE' });\n fetchPayments();\n fetchFilterOptions();\n } catch (err) {\n console.error('Failed to delete payment:', err);\n }\n };\n\n const handleUpdateStatus = async (id, status) => {\n try {\n await fetch(`${API_BASE}/${id}`, {\n method: 'PATCH',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ status }),\n });\n fetchPayments();\n } catch (err) {\n console.error('Failed to update status:', err);\n }\n };\n\n const handleFilterChange = (newFilters) => {\n setFilters(newFilters);\n setPage(1);\n };\n\n const handleSort = (field) => {\n if (sortBy === field) {\n setSortDir(d => d === 'asc' ? 'desc' : 'asc');\n } else {\n setSortBy(field);\n setSortDir('desc');\n }\n setPage(1);\n };\n\n const totalPages = Math.ceil(total / 50);\n\n return (\n <div className=\"min-h-screen bg-gray-50\">\n <header className=\"bg-white border-b border-gray-200 shadow-sm\">\n <div className=\"max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-3\">\n <div className=\"bg-indigo-600 p-2 rounded-lg\">\n <LayoutDashboard className=\"w-6 h-6 text-white\" />\n </div>\n <div>\n <h1 className=\"text-xl font-bold text-gray-900\">Finance Hub</h1>\n <p className=\"text-sm text-gray-500\">{total} transaction{total !== 1 ? 's' : ''} total</p>\n </div>\n </div>\n\n <div className=\"flex items-center gap-2\">\n {/* Tab switcher */}\n <div className=\"flex items-center rounded-lg border border-gray-200 bg-gray-50 p-1 gap-1\">\n <button\n onClick={() => setActiveTab('payments')}\n className={`flex items-center gap-1.5 px-3 py-1.5 text-sm font-medium rounded-md transition-colors ${\n activeTab === 'payments'\n ? 'bg-white text-indigo-700 shadow-sm'\n : 'text-gray-600 hover:text-gray-900'\n }`}\n >\n <LayoutDashboard className=\"w-4 h-4\" />\n Payments\n </button>\n <button\n onClick={() => setActiveTab('upload')}\n className={`flex items-center gap-1.5 px-3 py-1.5 text-sm font-medium rounded-md transition-colors ${\n activeTab === 'upload'\n ? 'bg-white text-emerald-700 shadow-sm'\n : 'text-gray-600 hover:text-gray-900'\n }`}\n >\n <Upload className=\"w-4 h-4\" />\n Upload CSV\n </button>\n </div>\n\n {activeTab === 'payments' && (\n <button\n onClick={() => { fetchPayments(); fetchFilterOptions(); }}\n className=\"flex items-center gap-2 px-3 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-lg hover:bg-gray-50 transition-colors\"\n >\n <RefreshCw className={`w-4 h-4 ${loading ? 'animate-spin' : ''}`} />\n Refresh\n </button>\n )}\n\n <button\n onClick={() => { window.location.href = '/outpost.goauthentik.io/sign_out'; }}\n className=\"flex items-center gap-2 px-3 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-lg hover:bg-gray-50 transition-colors\"\n title=\"Sign out\"\n >\n <LogOut className=\"w-4 h-4\" />\n </button>\n </div>\n </div>\n </div>\n </header>\n\n <main className=\"max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6\">\n {activeTab === 'payments' ? (\n <>\n <FilterBar\n filters={filters}\n filterOptions={filterOptions}\n onFilterChange={handleFilterChange}\n />\n\n <PaymentTable\n payments={payments}\n loading={loading}\n sortBy={sortBy}\n sortDir={sortDir}\n onSort={handleSort}\n onSend={(id) => handleAction(id, 'send')}\n onSkip={(id) => handleAction(id, 'skip')}\n onAddTag={handleAddTag}\n onRemoveTag={handleRemoveTag}\n onDelete={handleDelete}\n onUpdateStatus={handleUpdateStatus}\n existingTags={filterOptions.tags}\n />\n\n {totalPages > 1 && (\n <div className=\"flex items-center justify-center gap-2 mt-6\">\n <button\n onClick={() => setPage(p => Math.max(1, p - 1))}\n disabled={page === 1}\n className=\"px-3 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-lg hover:bg-gray-50 disabled:opacity-50 disabled:cursor-not-allowed\"\n >\n Previous\n </button>\n <span className=\"text-sm text-gray-600\">\n Page {page} of {totalPages}\n </span>\n <button\n onClick={() => setPage(p => Math.min(totalPages, p + 1))}\n disabled={page === totalPages}\n className=\"px-3 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-lg hover:bg-gray-50 disabled:opacity-50 disabled:cursor-not-allowed\"\n >\n Next\n </button>\n </div>\n )}\n </>\n ) : (\n <UploadPanel onUploadSuccess={handleUploadSuccess} />\n )}\n </main>\n </div>\n );\n}","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"FilterBar.jsx","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"FilterBar.jsx","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"167 lines","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"import React, { useState, useEffect } from 'react';\nimport { Search, Filter, X, Calendar, ChevronDown, ChevronUp } from 'lucide-react';\n\nconst STATUS_OPTIONS = [\n { value: '', label: 'All Statuses' },\n { value: 'UNPROCESSED', label: 'Unprocessed' },\n { value: 'SENT', label: 'Sent' },\n { value: 'SKIPPED', label: 'Skipped' },\n];\n\nconst SOURCE_OPTIONS = [\n { value: '', label: 'All Sources' },\n { value: 'INGEST', label: 'SMS Ingest' },\n { value: 'UPLOAD', label: 'CSV Upload' },\n];\n\nexport default function FilterBar({ filters, filterOptions, onFilterChange }) {\n const [search, setSearch] = useState(filters.search || '');\n const [isOpen, setIsOpen] = useState(() => window.innerWidth >= 768);\n\n useEffect(() => {\n const mq = window.matchMedia('(min-width: 768px)');\n const handler = (e) => setIsOpen(e.matches);\n mq.addEventListener('change', handler);\n return () => mq.removeEventListener('change', handler);\n }, []);\n\n const handleSearchSubmit = (e) => {\n e.preventDefault();\n onFilterChange({ ...filters, search: search || undefined });\n };\n\n const handleSelectChange = (key, value) => {\n const newFilters = { ...filters };\n if (value) {\n newFilters[key] = value;\n } else {\n delete newFilters[key];\n }\n onFilterChange(newFilters);\n };\n\n const clearFilters = () => {\n setSearch('');\n onFilterChange({});\n };\n\n const activeFilterCount = Object.keys(filters).length;\n const hasActiveFilters = activeFilterCount > 0;\n\n return (\n <div className=\"bg-white rounded-xl border border-gray-200 shadow-sm p-4 mb-6\">\n <button\n onClick={() => setIsOpen(!isOpen)}\n className=\"w-full flex items-center gap-2\"\n >\n <Filter className=\"w-4 h-4 text-gray-500\" />\n <span className=\"text-sm font-medium text-gray-700\">Filters</span>\n {hasActiveFilters && (\n <span className=\"inline-flex items-center justify-center w-5 h-5 text-xs font-bold text-white bg-indigo-600 rounded-full\">\n {activeFilterCount}\n </span>\n )}\n {hasActiveFilters && (\n <span\n onClick={(e) => { e.stopPropagation(); clearFilters(); }}\n className=\"ml-1 flex items-center gap-1 text-xs text-red-600 hover:text-red-700\"\n >\n <X className=\"w-3 h-3\" />\n Clear\n </span>\n )}\n <span className=\"ml-auto\">\n {isOpen\n ? <ChevronUp className=\"w-4 h-4 text-gray-400\" />\n : <ChevronDown className=\"w-4 h-4 text-gray-400\" />\n }\n </span>\n </button>\n\n {isOpen && (\n <div className=\"space-y-3 mt-3 pt-3 border-t border-gray-100\">\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-5 gap-3\">\n <form onSubmit={handleSearchSubmit} className=\"relative\">\n <Search className=\"absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400\" />\n <input\n type=\"text\"\n placeholder=\"Search...\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n onBlur={() => onFilterChange({ ...filters, search: search || undefined })}\n className=\"w-full pl-9 pr-3 py-2 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 outline-none\"\n />\n </form>\n\n <select\n value={filters.source || ''}\n onChange={(e) => handleSelectChange('source', e.target.value)}\n className=\"w-full py-2 px-3 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 outline-none bg-white\"\n >\n {SOURCE_OPTIONS.map(opt => (\n <option key={opt.value} value={opt.value}>{opt.label}</option>\n ))}\n </select>\n\n <select\n value={filters.status || ''}\n onChange={(e) => handleSelectChange('status', e.target.value)}\n className=\"w-full py-2 px-3 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 outline-none bg-white\"\n >\n {STATUS_OPTIONS.map(opt => (\n <option key={opt.value} value={opt.value}>{opt.label}</option>\n ))}\n </select>\n\n <select\n value={filters.type || ''}\n onChange={(e) => handleSelectChange('type', e.target.value)}\n className=\"w-full py-2 px-3 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 outline-none bg-white\"\n >\n <option value=\"\">All Types</option>\n {(filterOptions.types || []).map(t => (\n <option key={t} value={t}>{t}</option>\n ))}\n </select>\n\n <select\n value={filters.tag || ''}\n onChange={(e) => handleSelectChange('tag', e.target.value)}\n className=\"w-full py-2 px-3 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 outline-none bg-white\"\n >\n <option value=\"\">All Tags</option>\n {(filterOptions.tags || []).map(t => (\n <option key={t.id} value={t.name}>{t.name}</option>\n ))}\n </select>\n </div>\n\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-3\">\n <div className=\"relative\">\n <Calendar className=\"absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400\" />\n <input\n type=\"date\"\n placeholder=\"From date\"\n value={filters.dateFrom || ''}\n onChange={(e) => handleSelectChange('dateFrom', e.target.value)}\n className=\"w-full pl-9 pr-3 py-2 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 outline-none\"\n />\n </div>\n\n <div className=\"relative\">\n <Calendar className=\"absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400\" />\n <input\n type=\"date\"\n placeholder=\"To date\"\n value={filters.dateTo || ''}\n onChange={(e) => handleSelectChange('dateTo', e.target.value)}\n className=\"w-full pl-9 pr-3 py-2 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 outline-none\"\n />\n </div>\n </div>\n </div>\n )}\n </div>\n );\n}","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"PaymentTable.jsx","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"PaymentTable.jsx","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"339 lines","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"import React, { useState } from 'react';\nimport {\n ArrowUpDown, ArrowUp, ArrowDown,\n Send, XCircle, CheckCircle, MinusCircle, Clock,\n Inbox, Plus, X, ChevronDown, ChevronUp, Trash2,\n} from 'lucide-react';\n\nconst STATUS_CONFIG = {\n UNPROCESSED: { label: 'Unprocessed', icon: Clock, color: 'bg-amber-100 text-amber-700' },\n SENT: { label: 'Sent', icon: CheckCircle, color: 'bg-green-100 text-green-700' },\n SKIPPED: { label: 'Skipped', icon: MinusCircle, color: 'bg-gray-100 text-gray-500' },\n};\n\nconst TAG_COLORS = [\n '#ef4444', '#f97316', '#eab308', '#22c55e', '#06b6d4',\n '#3b82f6', '#8b5cf6', '#ec4899', '#6b7280',\n];\n\nconst COLUMNS = [\n { key: 'date', label: 'Date & Time', sortable: true },\n { key: 'source', label: 'Source', sortable: true },\n { key: 'type', label: 'Type', sortable: true },\n { key: 'recipient', label: 'Recipient', sortable: true },\n { key: 'amount', label: 'Amount', sortable: true },\n { key: 'balance', label: 'Balance', sortable: true },\n { key: 'status', label: 'Status', sortable: true },\n { key: 'tags', label: 'Tags', sortable: false },\n { key: 'actions', label: 'Actions', sortable: false },\n];\n\nfunction SortIcon({ column, sortBy, sortDir }) {\n if (sortBy !== column) return <ArrowUpDown className=\"w-3 h-3 text-gray-400\" />;\n return sortDir === 'asc'\n ? <ArrowUp className=\"w-3 h-3 text-indigo-600\" />\n : <ArrowDown className=\"w-3 h-3 text-indigo-600\" />;\n}\n\nfunction SourceBadge({ source }) {\n if (source === 'UPLOAD') {\n return (\n <span className=\"px-2 py-0.5 text-xs font-medium rounded bg-emerald-50 text-emerald-700\">\n CSV\n </span>\n );\n }\n return (\n <span className=\"px-2 py-0.5 text-xs font-medium rounded bg-indigo-50 text-indigo-700\">\n SMS\n </span>\n );\n}\n\nfunction TagCell({ payment, onAddTag, onRemoveTag, existingTags }) {\n const [open, setOpen] = useState(false);\n const [newTagName, setNewTagName] = useState('');\n const [newTagColor, setNewTagColor] = useState('#3b82f6');\n\n const paymentTags = payment.tags || [];\n const availableTags = existingTags.filter(t => !paymentTags.some(pt => pt.id === t.id));\n\n const handleAdd = (e) => {\n e.preventDefault();\n if (newTagName.trim()) {\n onAddTag(payment.id, newTagName.trim(), newTagColor);\n setNewTagName('');\n setOpen(false);\n }\n };\n\n return (\n <div className=\"flex flex-wrap items-center gap-1\">\n {paymentTags.map(tag => (\n <span\n key={tag.id}\n className=\"inline-flex items-center gap-0.5 px-1.5 py-0.5 text-xs font-medium rounded-full text-white\"\n style={{ backgroundColor: tag.color }}\n >\n {tag.name}\n <button onClick={() => onRemoveTag(payment.id, tag.id)} className=\"hover:opacity-75\">\n <X className=\"w-2.5 h-2.5\" />\n </button>\n </span>\n ))}\n <div className=\"relative\">\n <button\n onClick={() => setOpen(!open)}\n className=\"inline-flex items-center gap-0.5 px-1.5 py-0.5 text-xs text-gray-500 border border-dashed border-gray-300 rounded-full hover:border-gray-400\"\n >\n <Plus className=\"w-2.5 h-2.5\" />\n </button>\n {open && (\n <div className=\"absolute z-20 top-full left-0 mt-1 bg-white border border-gray-200 rounded-lg shadow-lg p-2 w-56\">\n <form onSubmit={handleAdd} className=\"flex items-center gap-1 mb-2\">\n <input\n type=\"text\"\n value={newTagName}\n onChange={(e) => setNewTagName(e.target.value)}\n placeholder=\"New tag\"\n autoFocus\n className=\"flex-1 px-2 py-1 text-xs border border-gray-300 rounded focus:ring-1 focus:ring-indigo-500 outline-none\"\n />\n <button type=\"submit\" className=\"text-xs text-indigo-600 font-medium hover:text-indigo-700 whitespace-nowrap\">Add</button>\n </form>\n <div className=\"flex gap-1 mb-2\">\n {TAG_COLORS.map(c => (\n <button\n key={c}\n type=\"button\"\n onClick={() => setNewTagColor(c)}\n className={`w-4 h-4 rounded-full border-2 ${newTagColor === c ? 'border-gray-800' : 'border-transparent'}`}\n style={{ backgroundColor: c }}\n />\n ))}\n </div>\n {availableTags.length > 0 && (\n <div className=\"border-t border-gray-100 pt-1 flex flex-wrap gap-1\">\n {availableTags.map(tag => (\n <button\n key={tag.id}\n onClick={() => { onAddTag(payment.id, tag.name, tag.color); setOpen(false); }}\n className=\"px-1.5 py-0.5 text-xs rounded-full border border-gray-200 text-gray-600 hover:bg-gray-100\"\n >\n {tag.name}\n </button>\n ))}\n </div>\n )}\n </div>\n )}\n </div>\n </div>\n );\n}\n\nfunction ExpandedRow({ payment }) {\n return (\n <tr className=\"bg-gray-50\">\n <td colSpan={COLUMNS.length} className=\"px-4 py-3\">\n <div className=\"text-xs text-gray-500 uppercase tracking-wide mb-1\">Original Message / Raw Data</div>\n <p className=\"text-sm text-gray-700 whitespace-pre-wrap break-words\">{payment.rawMessage}</p>\n {payment.debitBgn != null && (\n <p className=\"text-xs text-gray-500 mt-1\">Debit: {payment.debitBgn.toFixed(2)} BGN</p>\n )}\n {payment.creditBgn != null && (\n <p className=\"text-xs text-gray-500 mt-0.5\">Credit: {payment.creditBgn.toFixed(2)} BGN</p>\n )}\n {payment.transactionType && (\n <p className=\"text-xs text-gray-500 mt-0.5\">Transaction type: {payment.transactionType}</p>\n )}\n {payment.payerAccount && (\n <p className=\"text-xs text-gray-500 mt-0.5\">Account: {payment.payerAccount}</p>\n )}\n {payment.notifiedAt && (\n <p className=\"text-xs text-green-600 mt-2\">\n Notified on {new Date(payment.notifiedAt).toLocaleString('en-GB')}\n {payment.notifyPhone && ` to ${payment.notifyPhone}`}\n </p>\n )}\n </td>\n </tr>\n );\n}\n\nfunction StatusCell({ payment, onUpdateStatus }) {\n const [open, setOpen] = useState(false);\n const statusCfg = STATUS_CONFIG[payment.status] || STATUS_CONFIG.UNPROCESSED;\n const StatusIcon = statusCfg.icon;\n\n return (\n <div className=\"relative\">\n <button\n onClick={() => setOpen(!open)}\n className={`inline-flex items-center gap-1 px-2 py-0.5 text-xs font-medium rounded-full cursor-pointer ${statusCfg.color}`}\n >\n <StatusIcon className=\"w-3 h-3\" />\n {statusCfg.label}\n </button>\n {open && (\n <div className=\"absolute z-20 top-full left-0 mt-1 bg-white border border-gray-200 rounded-lg shadow-lg py-1 w-36\">\n {Object.entries(STATUS_CONFIG).map(([key, cfg]) => {\n const Icon = cfg.icon;\n return (\n <button\n key={key}\n onClick={() => { onUpdateStatus(payment.id, key); setOpen(false); }}\n className={`w-full flex items-center gap-2 px-3 py-1.5 text-xs hover:bg-gray-50 ${payment.status === key ? 'font-bold' : ''}`}\n >\n <Icon className=\"w-3 h-3\" />\n {cfg.label}\n </button>\n );\n })}\n </div>\n )}\n </div>\n );\n}\n\nexport default function PaymentTable({\n payments, loading, sortBy, sortDir, onSort,\n onSend, onSkip, onAddTag, onRemoveTag, onDelete, onUpdateStatus, existingTags,\n}) {\n const [expandedId, setExpandedId] = useState(null);\n\n if (loading) {\n return (\n <div className=\"flex items-center justify-center py-20\">\n <div className=\"animate-spin rounded-full h-8 w-8 border-b-2 border-indigo-600\"></div>\n </div>\n );\n }\n\n if (!payments || payments.length === 0) {\n return (\n <div className=\"flex flex-col items-center justify-center py-20 text-gray-400\">\n <Inbox className=\"w-12 h-12 mb-3\" />\n <p className=\"text-lg font-medium\">No transactions found</p>\n <p className=\"text-sm\">Try adjusting your filters, ingest a payment SMS, or upload a CSV.</p>\n </div>\n );\n }\n\n const formatDate = (d) => {\n if (!d) return '—';\n return new Date(d).toLocaleDateString('en-GB', {\n day: '2-digit', month: 'short', year: 'numeric', hour: '2-digit', minute: '2-digit',\n });\n };\n\n const formatAmount = (v, currency) =>\n v != null ? `${v.toFixed(2)} ${currency || 'EUR'}` : '—';\n\n return (\n <div className=\"bg-white rounded-xl border border-gray-200 shadow-sm overflow-hidden\">\n <div className=\"overflow-x-auto\">\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"bg-gray-50 border-b border-gray-200\">\n {COLUMNS.map(col => (\n <th\n key={col.key}\n className={`px-4 py-3 text-left text-xs font-semibold text-gray-600 uppercase tracking-wider ${col.sortable ? 'cursor-pointer select-none hover:bg-gray-100' : ''}`}\n onClick={() => col.sortable && onSort(col.key)}\n >\n <span className=\"inline-flex items-center gap-1\">\n {col.label}\n {col.sortable && <SortIcon column={col.key} sortBy={sortBy} sortDir={sortDir} />}\n </span>\n </th>\n ))}\n </tr>\n </thead>\n <tbody className=\"divide-y divide-gray-100\">\n {payments.map(p => {\n const isExpanded = expandedId === p.id;\n return (\n <React.Fragment key={p.id}>\n <tr className=\"hover:bg-gray-50 transition-colors\">\n <td className=\"px-4 py-3 whitespace-nowrap text-gray-700\">{formatDate(p.date)}</td>\n <td className=\"px-4 py-3 whitespace-nowrap\">\n <SourceBadge source={p.source} />\n </td>\n <td className=\"px-4 py-3 whitespace-nowrap\">\n {p.type ? (\n <span className=\"px-2 py-0.5 text-xs font-medium rounded bg-blue-50 text-blue-700\">{p.type}</span>\n ) : (p.transactionType ? (\n <span className=\"px-2 py-0.5 text-xs font-medium rounded bg-gray-100 text-gray-600 max-w-24 truncate block\" title={p.transactionType}>{p.transactionType}</span>\n ) : '—')}\n </td>\n <td className=\"px-4 py-3 text-gray-700 max-w-xs truncate\" title={p.recipient || ''}>\n <div className=\"flex items-center gap-1\">\n <span className=\"truncate\">{p.recipient || '—'}</span>\n <button\n onClick={() => setExpandedId(isExpanded ? null : p.id)}\n className=\"flex-shrink-0 text-gray-400 hover:text-gray-600\"\n title=\"Show raw data\"\n >\n {isExpanded ? <ChevronUp className=\"w-3.5 h-3.5\" /> : <ChevronDown className=\"w-3.5 h-3.5\" />}\n </button>\n </div>\n </td>\n <td className=\"px-4 py-3 whitespace-nowrap font-medium text-gray-900\">\n {formatAmount(p.amount, p.currency)}\n </td>\n <td className=\"px-4 py-3 whitespace-nowrap text-gray-600\">\n {formatAmount(p.balance, p.currency)}\n </td>\n <td className=\"px-4 py-3 whitespace-nowrap\">\n <StatusCell payment={p} onUpdateStatus={onUpdateStatus} />\n </td>\n <td className=\"px-4 py-3\">\n <TagCell\n payment={p}\n onAddTag={onAddTag}\n onRemoveTag={onRemoveTag}\n existingTags={existingTags}\n />\n </td>\n <td className=\"px-4 py-3 whitespace-nowrap\">\n <div className=\"flex items-center gap-1.5\">\n {p.status === 'UNPROCESSED' && (\n <>\n <button\n onClick={() => onSend(p.id)}\n className=\"inline-flex items-center gap-1 px-2.5 py-1 text-xs font-medium text-white bg-indigo-600 rounded-md hover:bg-indigo-700 transition-colors\"\n >\n <Send className=\"w-3 h-3\" />\n Send\n </button>\n <button\n onClick={() => onSkip(p.id)}\n className=\"inline-flex items-center gap-1 px-2.5 py-1 text-xs font-medium text-gray-600 bg-white border border-gray-300 rounded-md hover:bg-gray-50 transition-colors\"\n >\n <XCircle className=\"w-3 h-3\" />\n Skip\n </button>\n </>\n )}\n <button\n onClick={() => { if (window.confirm('Delete this transaction?')) onDelete(p.id); }}\n className=\"inline-flex items-center gap-1 px-2 py-1 text-xs font-medium text-red-600 bg-white border border-red-200 rounded-md hover:bg-red-50 transition-colors\"\n title=\"Delete transaction\"\n >\n <Trash2 className=\"w-3 h-3\" />\n </button>\n </div>\n </td>\n </tr>\n {isExpanded && <ExpandedRow payment={p} />}\n </React.Fragment>\n );\n })}\n </tbody>\n </table>\n </div>\n </div>\n );\n}","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"UploadPanel.jsx","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"UploadPanel.jsx","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"192 lines","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"import React, { useState, useRef } from 'react';\nimport { Upload, FileText, CheckCircle, AlertCircle, X, ArrowLeft } from 'lucide-react';\n\nexport default function UploadPanel({ onUploadSuccess }) {\n const [files, setFiles] = useState([]);\n const [loading, setLoading] = useState(false);\n const [result, setResult] = useState(null);\n const [error, setError] = useState(null);\n const [dragging, setDragging] = useState(false);\n const fileInputRef = useRef();\n\n const addFiles = (incoming) => {\n const csvFiles = Array.from(incoming).filter(f =>\n f.name.toLowerCase().endsWith('.csv')\n );\n setFiles(prev => {\n const existingNames = new Set(prev.map(f => f.name));\n return [...prev, ...csvFiles.filter(f => !existingNames.has(f.name))];\n });\n };\n\n const handleDrop = (e) => {\n e.preventDefault();\n setDragging(false);\n addFiles(e.dataTransfer.files);\n };\n\n const handleFileSelect = (e) => {\n addFiles(e.target.files);\n e.target.value = '';\n };\n\n const removeFile = (idx) => setFiles(prev => prev.filter((_, i) => i !== idx));\n\n const handleUpload = async () => {\n if (!files.length) return;\n setLoading(true);\n setError(null);\n setResult(null);\n\n const formData = new FormData();\n files.forEach(f => formData.append('files', f));\n\n try {\n const res = await fetch('/api/upload/csv', { method: 'POST', body: formData });\n const data = await res.json();\n if (!res.ok) throw new Error(data.error || 'Upload failed');\n setResult(data);\n setFiles([]);\n } catch (err) {\n setError(err.message);\n } finally {\n setLoading(false);\n }\n };\n\n return (\n <div className=\"max-w-2xl mx-auto\">\n <div className=\"mb-6\">\n <h2 className=\"text-lg font-semibold text-gray-900\">Upload DSK Bank CSV</h2>\n <p className=\"text-sm text-gray-500 mt-1\">\n Import transactions from DSK Bank CSV exports. Multiple files are merged automatically.\n Internal transfers are skipped. Tags are auto-assigned based on payee and description.\n </p>\n </div>\n\n {/* Drop zone */}\n <div\n onDrop={handleDrop}\n onDragOver={(e) => { e.preventDefault(); setDragging(true); }}\n onDragLeave={() => setDragging(false)}\n onClick={() => fileInputRef.current.click()}\n className={`border-2 border-dashed rounded-xl p-12 text-center cursor-pointer transition-colors ${\n dragging\n ? 'border-emerald-400 bg-emerald-50'\n : 'border-gray-300 hover:border-emerald-400 hover:bg-emerald-50'\n }`}\n >\n <Upload className={`w-10 h-10 mx-auto mb-3 ${dragging ? 'text-emerald-500' : 'text-gray-400'}`} />\n <p className=\"text-sm font-medium text-gray-700\">Drop DSK Bank CSV files here</p>\n <p className=\"text-xs text-gray-500 mt-1\">or click to select files — multiple files supported</p>\n <input\n ref={fileInputRef}\n type=\"file\"\n multiple\n accept=\".csv\"\n className=\"hidden\"\n onChange={handleFileSelect}\n />\n </div>\n\n {/* File list */}\n {files.length > 0 && (\n <div className=\"mt-4 space-y-2\">\n {files.map((f, i) => (\n <div key={i} className=\"flex items-center gap-2 bg-white rounded-lg border border-gray-200 px-3 py-2\">\n <FileText className=\"w-4 h-4 text-gray-400 flex-shrink-0\" />\n <span className=\"text-sm text-gray-700 flex-1 truncate\">{f.name}</span>\n <span className=\"text-xs text-gray-400 flex-shrink-0\">{(f.size / 1024).toFixed(1)} KB</span>\n <button\n onClick={(e) => { e.stopPropagation(); removeFile(i); }}\n className=\"text-gray-400 hover:text-gray-600 flex-shrink-0\"\n >\n <X className=\"w-4 h-4\" />\n </button>\n </div>\n ))}\n\n <button\n onClick={handleUpload}\n disabled={loading}\n className=\"w-full py-2.5 text-sm font-medium text-white bg-emerald-600 rounded-lg hover:bg-emerald-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors mt-2\"\n >\n {loading\n ? 'Importing…'\n : `Import ${files.length} file${files.length !== 1 ? 's' : ''}`\n }\n </button>\n </div>\n )}\n\n {/* Success result */}\n {result && (\n <div className=\"mt-6 bg-green-50 border border-green-200 rounded-xl p-5\">\n <div className=\"flex items-center gap-2 mb-3\">\n <CheckCircle className=\"w-5 h-5 text-green-600 flex-shrink-0\" />\n <span className=\"font-medium text-green-800\">Import complete</span>\n </div>\n <div className=\"grid grid-cols-3 gap-3 text-center mb-3\">\n <div className=\"bg-white rounded-lg border border-green-100 py-2 px-3\">\n <p className=\"text-2xl font-bold text-green-700\">{result.imported}</p>\n <p className=\"text-xs text-gray-500\">Imported</p>\n </div>\n <div className=\"bg-white rounded-lg border border-green-100 py-2 px-3\">\n <p className=\"text-2xl font-bold text-gray-500\">{result.skipped}</p>\n <p className=\"text-xs text-gray-500\">Skipped</p>\n </div>\n <div className=\"bg-white rounded-lg border border-green-100 py-2 px-3\">\n <p className=\"text-2xl font-bold text-amber-600\">{result.errors?.length ?? 0}</p>\n <p className=\"text-xs text-gray-500\">Warnings</p>\n </div>\n </div>\n <p className=\"text-xs text-gray-500 mb-3\">\n Skipped rows are internal bank transfers (ТРАНСФЕР СОБСТВЕНИ СМЕТКИ).\n </p>\n {result.errors?.length > 0 && (\n <details className=\"mb-3\">\n <summary className=\"text-xs text-amber-700 cursor-pointer hover:text-amber-800\">\n Show {result.errors.length} warning{result.errors.length !== 1 ? 's' : ''}\n </summary>\n <ul className=\"mt-2 text-xs text-amber-600 space-y-0.5 max-h-32 overflow-y-auto\">\n {result.errors.map((e, i) => <li key={i} className=\"font-mono\">{e}</li>)}\n </ul>\n </details>\n )}\n <button\n onClick={onUploadSuccess}\n className=\"flex items-center gap-1.5 text-sm font-medium text-green-700 hover:text-green-800\"\n >\n <ArrowLeft className=\"w-4 h-4\" />\n View imported transactions\n </button>\n </div>\n )}\n\n {/* Error */}\n {error && (\n <div className=\"mt-4 bg-red-50 border border-red-200 rounded-xl p-4 flex items-start gap-3\">\n <AlertCircle className=\"w-5 h-5 text-red-500 flex-shrink-0 mt-0.5\" />\n <div>\n <p className=\"text-sm font-medium text-red-800\">Upload failed</p>\n <p className=\"text-sm text-red-700 mt-0.5\">{error}</p>\n </div>\n </div>\n )}\n\n {/* Info box */}\n {!result && !error && (\n <div className=\"mt-6 bg-blue-50 border border-blue-100 rounded-xl p-4\">\n <p className=\"text-xs font-medium text-blue-800 mb-1\">Expected CSV format (DSK Bank export)</p>\n <p className=\"text-xs text-blue-700 font-mono\">\n Дата, Вид на трансакцията, Основание, Дебит BGN, Кредит BGN, Наредител/Получател, Номер сметка...\n </p>\n <p className=\"text-xs text-blue-600 mt-2\">\n Both UTF-8 and Windows-1251 encodings are supported. Tags are auto-applied based on payee and description keywords.\n </p>\n </div>\n )}\n </div>\n );\n}","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"PaymentCard.jsx","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"PaymentCard.jsx","depth":25,"on_screen":false,"role_description":"text"}]...
|
9123336834367040371
|
6809287908150012859
|
idle
|
accessibility
|
NULL
|
Explorer (⇧⌘E)
Search (⇧⌘F)
Source Control (⌃⇧ Explorer (⇧⌘E)
Search (⇧⌘F)
Source Control (⌃⇧G)
Run and Debug (⇧⌘D)
Remote Explorer
Extensions (⇧⌘X) - 2 require update
2
Claude Code
Containers
EXPLORER
EXPLORER
Explorer Section: finance [SSH: nas]
Explorer Section: finance [SSH: nas]
FINANCE [SSH: NAS]
auth
dsk-uploader
finance-hub
backend
frontend
.env
.env.example
.gitignore
docker-compose.yml
payments-logger
Outline Section
OUTLINE
OUTLINE
Timeline Section
TIMELINE
TIMELINE
docker-compose.yml, Editor Group 1
.env, Editor Group 1
report(1).csv, Editor Group 1
"Дата","Основание","Наредител/Получател","Номер сметка на наредителя / получателя","Вид на трансакцията","Свързваща референция","Валутен курс","Сума във валутата на превода","Дебит EUR","Кредит EUR"
"08.05.2026","400915xxxxxx4447 ПОС 08.05.2026 18:46<br/>Авт. код: 36C1UB","","","","","","","5,02",""
"08.05.2026","400915xxxxxx4447 ПОС 08.05.2026 18:36<br/>Авт. код: 5CK9TB","","","","","","","15,46",""
"08.05.2026","400915xxxxxx4447 ПОС 08.05.2026 18:07<br/>Авт. код: 8FK4TB","","","","","","","9,04",""
"08.05.2026","400915xxxxxx4447 ПЛАЩАНЕ НА ПОС 08.05.2026 19:32<br/>Авт. код: 6NM31C<br/>Номер на у-во: V5411421","BGR SOFIYA LIDL BALGARIYA EOOD UL TODOR","","КАРТОВА ОПЕРАЦИЯ","","","","67,81",""
"08.05.2026","400915xxxxxx4447 ПЛАЩАНЕ НА ПОС 07.05.2026 09:02<br/>Авт. код: 7NE8N7<br/>Номер на у-во: 10101446","BGR SOFIA CBA EKO MARKET","","КАРТОВА ОПЕРАЦИЯ","","","","5,51",""
"08.05.2026","400915xxxxxx4447 ПЛАЩАНЕ НА ПОС 06.05.2026 13:16<br/>Авт. код: 1TV886<br/>Номер на у-во: 06030191","POL BALICE Lagardere Travel R KR3","","КАРТОВА ОПЕРАЦИЯ","","","","5,49",""
"Дата","Основание","Наредител/Получател","Номер сметка на наредителя / получателя","Вид на трансакцията","Свързваща референция","Валутен курс","Сума във валутата на превода","Дебит EUR","Кредит EUR"
"08.05.2026","400915xxxxxx4447 ПОС 08.05.2026 18:46<br/>Авт. код: 36C1UB","","","","","","","5,02",""
"08.05.2026","400915xxxxxx4447 ПОС 08.05.2026 18:36<br/>Авт. код: 5CK9TB","","","","","","","15,46",""
"08.05.2026","400915xxxxxx4447 ПОС 08.05.2026 18:07<br/>Авт. код: 8FK4TB","","","","","","","9,04",""
"08.05.2026","400915xxxxxx4447 ПЛАЩАНЕ НА ПОС 08.05.2026 19:32<br/>Авт. код: 6NM31C<br/>Номер на у-во: V5411421","BGR SOFIYA LIDL BALGARIYA EOOD UL TODOR","","КАРТОВА ОПЕРАЦИЯ","","","","67,81",""
"08.05.2026","400915xxxxxx4447 ПЛАЩАНЕ НА ПОС 07.05.2026 09:02<br/>Авт. код: 7NE8N7<br/>Номер на у-во: 10101446","BGR SOFIA CBA EKO MARKET","","КАРТОВА ОПЕРАЦИЯ","","","","5,51",""
"08.05.2026","400915xxxxxx4447 ПЛАЩАНЕ НА ПОС 06.05.2026 13:16<br/>Авт. код: 1TV886<br/>Номер на у-во: 06030191","POL BALICE Lagardere Travel R KR3","","КАРТОВА ОПЕРАЦИЯ","","","","5,49",""
Design new payment-logge…, Editor Group 2
remote SSH: nas
SSH: nas
No Problems
0
0
No Ports Forwarded
0
Notifications
Sign In
Sign In
Info: Do you want to install the recommended 'Rainbow CSV' extension from mechatroner for report(1).csv?
Design new payment-logger and dsk-uploader hybrid app
Session history
New session
Message actions
payments.js
payments.js
ets create a new app that should be combination of payment-logger and dsk-uploader. It should have authorization via authentik (auth folder). All three folders (payment-logger, dsk-uploader and auth) are just refference these will be removed later. Auth project is separated it lives on its own. First reveiw them and see how these should be combined. It will be whole new app (also the folder name). Think very carefully of whatr these two apps do and how cold they be combined. THerer should be common db and uploader should store data the same way the /ingest does. It should be properly marked in UI if it is upload or ingest or both. FIrst think of tech stack and plan carefully.
Thinking
Thinking
I'll explore all three reference projects in parallel to understand their structure before planning.
Agent:
Explore payment-logger app structure and functionality
IN
Explore the /volume2/docker/finance/payments-logger directory thoroughly. I need to understand:
1. Tech stack (frontend framework, backend framework, database)
2. What the app does - its core purpose and features
3. Database schema - all tables, relationships
4. API routes - all endpoints, their purpose and request/response shapes
5. How data flows (ingest, storage, retrieval)
6. Any auth/middleware setup
7. Docker/deployment setup
8. Key files and their roles
Report with: directory structure, tech stack summary, database schema details, all API endpoints listed, UI features, and how data is ingested. Be thorough on the /ingest endpoint specifically.
Agent:
Explore dsk-uploader app structure and functionality
IN
Explore the /volume2/docker/finance/dsk-uploader directory thoroughly. I need to understand:
1. Tech stack (frontend framework, backend framework, database)
2. What the app does - its core purpose and features
3. Database schema - all tables, relationships
4. API routes - all endpoints, their purpose and request/response shapes
5. How file uploads work - what files, what format, how parsed
6. Any auth/middleware setup
7. Docker/deployment setup
8. Key files and their roles
Report with: directory structure, tech stack summary, database schema details, all API endpoints listed, UI features, how file upload parsing works, and what data is extracted from uploads. Be very thorough about the data model and what fields are stored.
Agent:
Explore auth folder and authentik integration
IN
Explore the /volume2/docker/finance/auth directory thoroughly. I need to understand:
1. What auth system is being used (Authentik)
2. How authentication/authorization is implemented - OAuth2, OIDC, session tokens, JWT?
3. Middleware - how is auth enforced on routes?
4. Any frontend auth flow - login redirect, token handling, protected routes
5. Environment variables related to auth
6. Docker/deployment setup for the auth service itself
7. Any example of how other apps integrate with this auth
Report with: directory structure, auth flow description, middleware code, environment variable names, and integration patterns. This is a reference for building auth into a new combined app.
Message actions
payments.js
payments.js
continue
Thinking
Thinking
Launching parallel exploration of all three reference projects.
Agent:
Explore payment-logger app structure
IN
Explore the /volume2/docker/finance/payments-logger directory thoroughly. I need to understand:
1. Full directory structure (tree)
2. Tech stack (frontend framework, backend framework, database, etc.)
3. What the app does - its core functionality
4. How data is ingested (look at /ingest route especially)
5. Database schema (what tables/collections exist)
6. API routes and their purposes
7. Frontend pages and components
8. Docker setup
9. Any auth/session handling
Please read key files: package.json files, main entry points, route files, database schema files, docker-compose.yml, and any frontend components. Be thorough - I need a complete picture to plan a new combined app.
Agent:
Explore dsk-uploader app structure
IN
Explore the /volume2/docker/finance/dsk-uploader directory thoroughly. I need to understand:
1. Full directory structure (tree)
2. Tech stack (frontend framework, backend framework, database, etc.)
3. What the app does - its core functionality
4. How file uploads work (what format, what processing happens)
5. Database schema (what tables/collections exist)
6. API routes and their purposes
7. Frontend pages and components
8. Docker setup
9. Any auth/session handling
Please read key files: package.json files, main entry points, route files, database schema files, docker-compose.yml, and any frontend components. Be thorough - I need a complete picture to plan a new combined app.
Agent:
Explore auth project structure
IN
Explore the /volume2/docker/finance/auth directory thoroughly. I need to understand:
1. Full directory structure (tree)
2. What authentication system is used (authentik integration details)
3. How OAuth/OIDC flow works
4. Any middleware or helper functions for protecting routes
5. Session management approach
6. How frontend handles auth state
7. Any example of how other apps integrate with this auth system
8. Docker setup and environment variables
Please read all files carefully - this auth system will be integrated into a new combined app. I need to understand exactly how to use it.
Thinking
Thinking
Now I have a complete picture of all three. Let me design the plan.
Agent:
Design combined app architecture
IN
Design a detailed implementation plan for a new combined web app that merges two existing applications. Here is full context:
---
## App 1: payments-logger (Node.js)
- **Purpose**: Ingest Bulgarian bank SMS → parse → store in PostgreSQL → review/tag/notify in React UI
- **Stack**: Node.js 20 + Express + Prisma 5 + PostgreSQL 16 + React 18 + Vite + Tailwind CSS
- **Auth**: Custom JWT (bcryptjs + jose), tokens in localStorage
- **Ingest**: POST /api/payments/ingest (public) — SMS text OR structured JSON (Apple Wallet)
- **Schema** (PostgreSQL via Prisma):
- `payments` table: id, raw_message, date, type (POS/ATM/INTERNET/ECOM/P2P/WALLET), card, recipient, amount, balance, status (UNPROCESSED/SENT/SKIPPED), notifyPhone, notifiedAt, created_at, updated_at
- `tags` table: id, name, color — M2M with payments via `_PaymentToTag`
- `users` table: id, username, hashed_password (this will be REMOVED)
- **UI**: Single-page React app — PaymentTable (sortable, filterable, taggable), FilterBar, status actions (send/skip), notification system
- **Parser** (backend/src/parser.js): Regex parser for Bulgarian DSK Bank SMS, extracts date/time (DD/MM/YYYY HH:MM), card mask, transaction type, recipient, amount, balance
## App 2: dsk-uploader (Python/Flask)
- **Purpose**: Upload DSK bank CSV exports → parse/normalize → upload to Notion database
- **Stack**: Python 3.11 + Flask + Pandas + Custom Notion SDK + Bootstrap 5
- **Auth**: None (open)
- **CSV format** (DSK Bank Bulgarian format, columns):
- `Дата` (date, DD.MM.YYYY)
- `Вид на трансакцията` (transaction type, Bulgarian)
- `Основание` (reason/description — contains card number regex: `^\d{6}x{6}\d{4}$`)
- `Дебит BGN` (debit amount, may be empty)
- `Кредит BGN` (credit amount, may be empty)
- `Наредител/Получател` (orderer/recipient name)
- `Номер сметка на наредителя / получателя` (account number)
- **Processing**: merge multiple CSVs, normalize dates, extract card numbers from reason via regex, auto-generate tags (keyword heuristics: ЗАПЛАТА→Salary, NETFLIX→Subscriptions, etc.), filter internal transfers
- **Output**: Notion database pages (this will be REPLACED with local PostgreSQL)
## App 3: auth (Authentik)
- **Mode**: Proxy mode via NPM (forward auth)
- **How it works**: NPM intercepts all requests, calls Authentik outpost's auth endpoint. On success, NPM injects headers into proxied request:
- `X-authentik-username`
- `X-authentik-email`
- `X-authentik-groups`
- **No code integration needed** in the app itself — just trust these headers from NPM
- **Logout**: Redirect user to `/outpost.goauthentik.io/sign_out`
---
## What the New Combined App Must Do
1. **Single PostgreSQL database** for all transactions
2. **SMS Ingest** (public endpoint) — same as payments-logger /ingest, source=INGEST
3. **CSV Upload** (authenticated) — parse DSK CSV files, store transactions with source=UPLOAD into the same DB schema
4. **Unified UI** — show all payments in one table regardless of source
5. **Source indicator** in UI — badge showing "INGEST", "UPLOAD", or "BOTH" (if duplicate detection added)
6. **Source filter** in FilterBar — filter by All/Ingest/Upload
7. **Authentik auth** — remove custom JWT entirely; trust X-authentik-* headers from NPM
8. **All existing payments-logger features**: tagging, send notification, skip, status tracking, filters, sorting, pagination
9. **Remove Notion dependency entirely** — all data stays in local PostgreSQL
---
## Technical Constraints
- Keep Node.js backend (not Python) — extend payments-logger's stack
- CSV parsing: use `csv-parse` npm package (handles encoding, streaming)
- File upload: use `multer` npm middleware
- Auth middleware: read X-authentik-username header, 401 if missing (but /api/payments/ingest stays public)
- Add `source` enum field (INGEST/UPLOAD) to payments schema
- Add `currency` field (EUR for SMS ingest, BGN for CSV uploads) — or just store as-is
- Remove `users` table from schema
---
## Please Design
1. Complete folder structure for the new app (suggest name: "finance-hub" or similar — note this is a placeholder, user will confirm)
2. Prisma schema with new fields (`source`, `currency`)
3. All backend API routes
4. CSV parser design in Node.js (port of the Python logic)
5. Authentik auth middleware
6. Frontend component structure (React) — what's reused from payments-logger, what's new
7. Docker Compose setup
8. Environment variables needed
9. Step-by-step implementation order
10. Verification checklist
Be specific about file paths and code structure. This will be used to write actual implementation code.
Thinking
Thinking
Good plan. Let me ask the one thing I need before writing the final plan.
AskUserQuestion
OUT
User has answered your questions: "What should the new combined app be called? This will be the folder name under /volume2/docker/finance/ and the app branding."="finance-hub". You can now continue with the user's answers in mind.
Thinking
Thinking
Writing the final plan now.
Thinking
Thinking
Write
ets-create-a-new-generic-sun.md
ets-create-a-new-generic-sun.md
326 lines
# finance-hub — Implementation Plan
## Context
Two separate finance apps exist as references and will be retired:
- **payments-logger** (Node.js/React): Ingests Bulgarian bank SMS notifications, stores payments in PostgreSQL, provides a review/tag/notify UI.
- **dsk-uploader** (Python/Flask): Uploads DSK bank CSV exports, parses them, sends to Notion.
The new app **finance-hub** (`/volume2/docker/finance/finance-hub/`) replaces both with a single unified system: all transactions (SMS-ingested and CSV-uploaded) land in one PostgreSQL database and one React UI. Authentication is delegated entirely to Authentik (proxy mode via NPM — no custom JWT).
---
## Tech Stack
| Layer | Choice | Rationale |
|-------|--------|-----------|
| Backend | Node.js 20 + Express + Prisma 5 | Extends payments-logger; no Python needed |
| CSV parsing | `csv-parse` + `iconv-lite` | Handles Bulgarian cp1251 encoding, RFC4180 quoted fields |
| File upload | `multer` (memory storage) | Bank CSVs are small (<500 KB), no disk cleanup needed |
| Database | PostgreSQL 16 | Same as payments-logger |
| Frontend | React 18 + Vite + Tailwind CSS + Lucide React | Same as payments-logger |
| Auth | Authentik proxy via NPM headers | No custom JWT; removes users table entirely |
| Container | Docker Compose | Same pattern as both reference apps |
**Removed vs payments-logger:** `bcryptjs`, `jose`, `users` table, login form, JWT storage.
**Removed vs dsk-uploader:** Python/Flask, Pandas, Notion SDK, all Notion references.
**Added:** `csv-parse`, `iconv-lite`, `multer`, `source` + `currency` fields, `UploadPanel` component.
---
## Folder Structure
```
/volume2/docker/finance/finance-hub/
├── docker-compose.yml
├── .env
├── .env.example
├── .gitignore
├── backend/
│ ├── Dockerfile
│ ├── package.json
│ ├── prisma/
│ │ ├── schema.prisma
│ │ └── migrations/
│ │ ├── migration_lock.toml
│ │ └── 20260508_init/
│ │ └── migration.sql
│ └── src/
│ ├── index.js ← entry point (Authentik middleware wired here)
│ ├── auth.js ← Authentik header middleware (replaces JWT auth)
│ ├── parser.js ← SMS parser (copy verbatim from payments-logger)
│ ├── csvParser.js ← NEW: DSK CSV parser (port of Python dskuploader.py)
│ └── routes/
│ ├── payments.js ← existing routes + source/currency additions
│ └── upload.js ← NEW: POST /api/upload/csv
└── frontend/
├── Dockerfile
├── package.json
├── vite.config.js
├── tailwind.config.js
├── postcss.config.js
├── index.html
└── src/
├── main.jsx ← remove AuthProvider wrapper
├── index.css
├── App.jsx ← remove auth state, add Upload tab toggle
└── components/
├── FilterBar.jsx ← add source filter select
├── PaymentTable.jsx ← add Source badge column + currency display
├── PaymentCard.jsx ← minor source badge addition
├── PaymentList.jsx ← unchanged
└── UploadPanel.jsx ← NEW: drag-and-drop CSV upload UI
```
---
## Database Schema (Prisma)
File: `backend/prisma/schema.prisma`
```prisma
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model Payment {
id Int @id @default(autoincrement())
rawMessage String @map("raw_message")
date DateTime?
type String?
card String?
recipient String?
amount Float?
currency String? @default("EUR")
balance Float?
source Source @default(INGEST)
status Status @default(UNPROCESSED)
tags Tag[]
notifiedAt DateTime? @map("notified_at")
notifyPhone String? @map("notify_phone")
debitBgn Float? @map("debit_bgn")
creditBgn Float? @map("credit_bgn")
transactionType String? @map("transaction_type")
payerAccount String? @map("payer_account")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@map("payments")
}
model Tag {
id Int @id @default(autoincrement())
name String @unique
color String @default("#6b7280")
payments Payment[]
@@map("tags")
}
enum Status { UNPROCESSED SENT SKIPPED }
enum Source { INGEST UPLOAD }
```
**Key decisions:**
- No `User` model — Authentik owns identity.
- `currency`: `EUR` for SMS ingest, `BGN` for CSV uploads.
- `debitBgn`, `creditBgn`, `transactionType`, `payerAccount`: nullable CSV-only columns; INGEST rows store nulls. Avoids a union query for the unified list view.
- `balance` is always null for CSV rows (DSK export does not include running balance).
- Fresh consolidated migration — no data migration from reference apps required.
---
## API Routes
| Method | Path | Auth | Description |
|--------|------|------|-------------|
| GET | /api/health | public | Health check |
| POST | /api/payments/ingest | public | SMS or structured ingest (source=INGEST) |
| GET | /api/payments | required | List with filters/sort/pagination (+ source filter) |
| GET | /api/payments/meta/tags | required | All tags |
| GET | /api/payments/meta/filters | required | Filter options incl. `sources` array |
| GET | /api/payments/:id | required | Single payment |
| PATCH | /api/payments/:id | required | Update status |
| DELETE | /api/payments/:id | required | Delete |
| POST | /api/payments/:id/send | required | Send notification |
| POST | /api/payments/:id/skip | required | Skip |
| POST | /api/payments/:id/tags | required | Add/upsert tag |
| DELETE | /api/payments/:id/tags/:tagId | required | Remove tag |
| POST | /api/upload/csv | required | DSK CSV file upload (source=UPLOAD) |
---
## Key Implementation Details
### auth.js (replaces entire old auth module)
```js
const PUBLIC_PATHS = new Set(['/api/health', '/api/payments/ingest']);
function authentikMiddleware(req, res, next) {
if (PUBLIC_PATHS.has(req.path)) return next();
const username = req.headers['x-authentik-username'];
if (!username) return res.status(401).json({ error: 'Unauthorized' });
req.user = {
username,
email: req.headers['x-authentik-email'] || null,
groups: (req.headers['x-authentik-groups'] || '').split(',').map(g => g.trim()).filter(Boolean),
};
next();
}
module.exports = { authentikMiddleware };
```
### csvParser.js (port of dskuploader.py)
- `iconv-lite` decodes buffer as cp1251 (DSK Bank export encoding), falls back to UTF-8
- `csv-parse` parses the decoded text with `columns: true`
- Columns: `Дата`, `Вид на трансакцията`, `Основание`, `Дебит BGN`, `Кредит BGN`, `Наредител/Получател`, `Номер сметка на наредителя / получателя`
- Card extraction: regex `/^\d{6}x{6}\d{4}$/` on first token of `Основание`
- Skips rows where `Вид на трансакцията === 'ТРАНСФЕР СОБСТВЕНИ СМЕТКИ'`
- Auto-tags via keyword rules (ЗАПЛАТА→Salary, LIDL→Groceries, NETFLIX→Subscriptions, etc.) — same logic as Python `generate_tags()`
- Returns `{ rows: PaymentData[], skipped: number, errors: string[] }`
### payments.js changes from payments-logger
1. Add `source: 'INGEST'` and `currency` to the `/ingest` create call
2. Add `source` to the `GET /` where clause filter
3. Add `sources` to `meta/filters` response
4. Currency-aware amount formatting in notification message
5. Remove all JWT/auth references (no `/auth/register`, `/auth/login`)
### upload.js (new)
- `multer` memory storage, max 10 files × 10 MB
- Calls `parseDskCsv(buffer)` per file
- Upserts tags via `prisma.tag.upsert` then connects
- Returns `{ imported, skipped, errors, payments[] }`
### Frontend changes
- **Delete**: `auth.js`, `AuthProvider.jsx`
- **main.jsx**: Remove `<AuthProvider>` wrapper
- **App.jsx**: Replace `authFetch` with plain `fetch` (Authentik session cookie travels automatically); logout → `window.location.href = '/outpost.goauthentik.io/sign_out'`; add "Payments" / "Upload CSV" tab toggle
- **FilterBar.jsx**: Add source `<select>` (All / SMS Ingest / CSV Upload); widen grid to 5 cols
- **PaymentTable.jsx**: Add `Source` column with `SMS` (indigo) / `CSV` (emerald) badge; show `${amount} ${currency}` in amount cell
- **UploadPanel.jsx** (new): Drag-and-drop zone + file list + import button + result summary with error accordion; calls `POST /api/upload/csv` with `FormData`
---
## Docker Compose
```yaml
services:
db:
image: postgres:16-alpine
environment: { POSTGRES_USER: finance, POSTGRES_PASSWORD: [PASSWORD] POSTGRES_DB: finance_hub }
volumes: [pgdata:/var/lib/postgresql/data]
healthcheck: { test: pg_isready -U finance -d finance_hub, interval: 5s }
backend:
build: ./backend
environment:
DATABASE_URL: [CONNECTION_STRING]
PORT: "3001"
NOTIFIER_URL: ${NOTIFIER_URL}
NOTIFIER_CHANNEL: ${NOTIFIER_CHANNEL:-viber}
NOTIFY_DEFAULT_PHONE: ${NOTIFY_DEFAULT_PHONE}
TZ: ${TZ:-Europe/Sofia}
ports: ["${BACKEND_PORT:-3001}:3001"]
depends_on: { db: { condition: service_healthy } }
frontend:
build: ./frontend
ports: ["${FRONTEND_PORT:-5175}:5173"]
depends_on: [backend]
volumes: { pgdata: }
```
**NPM setup:** Frontend port proxied through Authentik forward auth. Backend port exposed separately (unprotected) so the public `/api/payments/ingest` remains reachable by iOS Shortcuts / SMS gateways without login.
---
## Environment Variables (.env)
```bash
[ENV_SECRET]
NOTIFIER_URL=[URL_WITH_CREDENTIALS] @default(autoincrement())
rawMessage String @map("raw_message")
date DateTime?
type String?
card String?
recipient String?
amount Float?
currency String? @default("EUR")
balance Float?
source Source @default(INGEST)
status Status @default(UNPROCESSED)
tags Tag[]
notifiedAt DateTime? @map("notified_at")
notifyPhone String? @map("notify_phone")
debitBgn Float? @map("debit_bgn")
creditBgn Float? @map("credit_bgn")
transactionType String? @map("transaction_type")
payerAccount String? @map("payer_account")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@map("payments")
}
model Tag {
id Int @id @default(autoincrement())
name String @unique
color String @default("#6b7280")
payments Payment[]
@@map("tags")
}
enum Status {
UNPROCESSED
SENT
SKIPPED
}
enum Source {
INGEST
UPLOAD
}
Write
migration.sql
migration.sql
55 lines
-- CreateEnum
CREATE TYPE "Status" AS ENUM ('UNPROCESSED', 'SENT', 'SKIPPED');
CREATE TYPE "Source" AS ENUM ('INGEST', 'UPLOAD');
-- CreateTable
CREATE TABLE "payments" (
"id" SERIAL PRIMARY KEY,
"raw_message" TEXT NOT NULL,
"date" TIMESTAMP(3),
"type" TEXT,
"card" TEXT,
"recipient" TEXT,
"amount" DOUBLE PRECISION,
"currency" TEXT DEFAULT 'EUR',
"balance" DOUBLE PRECISION,
"source" "Source" NOT NULL DEFAULT 'INGEST',
"status" "Status" NOT NULL DEFAULT 'UNPROCESSED',
"notified_at" TIMESTAMP(3),
"notify_phone" TEXT,
"debit_bgn" DOUBLE PRECISION,
"credit_bgn" DOUBLE PRECISION,
"transaction_type" TEXT,
"payer_account" TEXT,
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP
);
-- CreateTable
CREATE TABLE "tags" (
"id" SERIAL PRIMARY KEY,
"name" TEXT NOT NULL,
"color" TEXT NOT NULL DEFAULT '#6b7280'
);
-- CreateUniqueIndex
CREATE UNIQUE INDEX "tags_name_key" ON "tags"("name");
-- CreateTable (M2M join)
CREATE TABLE "_PaymentToTag" (
"A" INTEGER NOT NULL,
"B" INTEGER NOT NULL,
CONSTRAINT "_PaymentToTag_AB_pkey" PRIMARY KEY ("A", "B")
);
CREATE INDEX "_PaymentToTag_B_index" ON "_PaymentToTag"("B");
-- AddForeignKey
ALTER TABLE "_PaymentToTag"
ADD CONSTRAINT "_PaymentToTag_A_fkey"
FOREIGN KEY ("A") REFERENCES "payments"("id") ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE "_PaymentToTag"
ADD CONSTRAINT "_PaymentToTag_B_fkey"
FOREIGN KEY ("B") REFERENCES "tags"("id") ON DELETE CASCADE ON UPDATE CASCADE;
Write
migration_lock.toml
migration_lock.toml
4 lines
# Please do not edit this file manually
# It should be added in your version-control system (e.g., Git)
provider = "postgresql"
Update Todos
Create folder structure and root config files
Write backend Prisma schema and migration
Write backend package.json and Dockerfile
Write backend src files (auth, parser, csvParser, index)
Write backend routes (payments.js, upload.js)
Write frontend config files
Write frontend React components
Build and verify with docker compose
Write
package.json
package.json
26 lines
{
"name": "finance-hub-backend",
"version": "1.0.0",
"main": "src/index.js",
"scripts": {
"start": "node src/index.js",
"dev": "nodemon src/index.js",
"prisma:generate": "prisma generate",
"prisma:migrate": "prisma migrate deploy"
},
"dependencies": {
"@prisma/client": "^5.22.0",
"cors": "^2.8.5",
"csv-parse": "^5.5.6",
"express": "^4.21.1",
"express-rate-limit": "^7.4.0",
"iconv-lite": "^0.6.3",
"morgan": "^1.10.0",
"multer": "^1.4.5-lts.1"
},
"devDependencies": {
"nodemon": "^3.1.7",
"prisma": "^5.22.0"
}
}
Write
Dockerfile
Dockerfile
18 lines
FROM node:20-alpine
RUN apk add --no-cache openssl
WORKDIR /app
COPY package.json package-lock.json* ./
RUN npm install
COPY prisma ./prisma
RUN npx prisma generate
COPY src ./src
EXPOSE 3001
CMD ["sh", "-c", "npx prisma migrate deploy && node src/index.js"]
Update Todos
Create folder structure and root config files
Write backend Prisma schema and migration
Write backend package.json and Dockerfile
Write backend src files (auth, parser, csvParser, index)
Write backend routes (payments.js, upload.js)
Write frontend config files
Write frontend React components
Build and verify with docker compose
Write
auth.js
auth.js
27 lines
const PUBLIC_PATHS = new Set([
'/api/health',
'/api/payments/ingest',
]);
function authentikMiddleware(req, res, next) {
if (PUBLIC_PATHS.has(req.path)) return next();
const username = req.headers['x-authentik-username'];
if (!username) {
return res.status(401).json({ error: 'Unauthorized — missing Authentik session' });
}
req.user = {
username,
email: req.headers['x-authentik-email'] || null,
groups: (req.headers['x-authentik-groups'] || '')
.split(',')
.map(g => g.trim())
.filter(Boolean),
};
next();
}
module.exports = { authentikMiddleware };
Write
parser.js
parser.js
104 lines
/**
* Parses SMS payment messages from Bulgarian banks (DSK Bank, etc.)
*
* Supported formats:
*
* POS / INTERNET / ECOM / P2P payment:
* DSK Bank. Na DD/MM/YYYY v HH:MM sa plateni AMOUNT CURRENCY s karta CARD na POS s adres: RECIPIENT. Nalichni: BALANCE CURRENCY.
*
* ATM withdrawal:
* DSK Bank. Na DD/MM/YYYY v HH:MM sa iztegleni AMOUNT CURRENCY s karta CARD ot ATM s adres: RECIPIENT. Nalichni: BALANCE CURRENCY.
*
* ATM utility payment (amount may include fee as AMOUNT/FEE):
* DSK Bank. Na DD/MM/YYYY v HH:MM sa plateni AMOUNT CURRENCY/FEE CURRENCY s karta CARD na ATM s adres:RECIPIENT. Nalichni: BALANCE CURRENCY.
*/
const LOCAL_TZ = process.env.TZ || 'Europe/Sofia';
/**
* Convert a local-timezone date/time to a UTC Date object.
* Uses Intl to resolve the actual UTC offset (DST-aware).
*/
function localToUtc(year, month, day, hour, minute) {
const naive = new Date(Date.UTC(year, month - 1, day, hour, minute, 0));
const formatter = new Intl.DateTimeFormat('en-US', {
timeZone: LOCAL_TZ,
year: 'numeric', month: '2-digit', day: '2-digit',
hour: '2-digit', minute: '2-digit', second: '2-digit',
hour12: false,
});
const parts = {};
formatter.formatToParts(naive).forEach(p => { parts[p.type] = p.value; });
const localAtNaive = new Date(Date.UTC(
parseInt(parts.year), parseInt(parts.month) - 1, parseInt(parts.day),
parseInt(parts.hour) % 24, parseInt(parts.minute), parseInt(parts.second),
));
const offsetMs = localAtNaive.getTime() - naive.getTime();
return new Date(Date.UTC(year, month - 1, day, hour, minute, 0) - offsetMs);
}
function parsePaymentSms(message) {
const result = {
rawMessage: message,
date: null,
type: null,
card: null,
recipient: null,
amount: null,
balance: null,
};
// Date and time: "Na DD/MM/YYYY v HH:MM"
const dateMatch = message.match(/Na (\d{2})\/(\d{2})\/(\d{4}) v (\d{2}):(\d{2})/i);
if (dateMatch) {
const [, day, month, year, hour, minute] = dateMatch;
result.date = localToUtc(
parseInt(year), parseInt(month), parseInt(day),
parseInt(hour), parseInt(minute),
);
}
// Card mask: "s karta 400915***4447" or "s karta 483890***7162"
const cardMatch = message.match(/s karta\s+([\d*]+)/i);
if (cardMatch) {
result.card = cardMatch[1];
}
// Transaction type: supports both prepositions
// "na POS" / "na ATM" / "na INTERNET" etc. (payment)
// "ot ATM" (withdrawal)
const typeMatch = message.match(/(?:na|ot)\s+(POS|ATM|INTERNET|ECOM|P2P)\b/i);
if (typeMatch) {
result.type = typeMatch[1].toUpperCase();
}
// Recipient address: "s adres: MERCHANT" or "s adres:MERCHANT" (no space variant)
const recipientMatch = message.match(/s adres:\s*([^.]+)\./i);
if (recipientMatch) {
result.recipient = recipientMatch[1].trim();
}
// Amount: handles both verbs and the AMOUNT/FEE suffix format
// "sa plateni 7.78 EUR"
// "sa iztegleni 400.00 EUR"
// "sa plateni 0.50 EUR/0.50 EUR" → captures 0.50 (the charged amount, ignoring fee)
const amountMatch = message.match(/sa (?:plateni|iztegleni)\s+([\d.,]+)\s+[A-Z]{3}/i);
if (amountMatch) {
result.amount = parseFloat(amountMatch[1].replace(',', '.'));
}
// Balance: "Nalichni: 2583.07 EUR."
const balanceMatch = message.match(/Nalichni:\s*([\d.,]+)\s+[A-Z]{3}/i);
if (balanceMatch) {
result.balance = parseFloat(balanceMatch[1].replace(',', '.'));
}
return result;
}
module.exports = { parsePaymentSms };
Write
csvParser.js
csvParser.js
175 lines
/**
* DSK Bank CSV parser — Node.js port of dskuploader.py
*
* DSK Bank exports use Windows-1251 (cp1251) encoding.
* Each row maps to a Payment record with source=UPLOAD, currency=BGN.
*/
const { parse } = require('csv-parse');
const iconv = require('iconv-lite');
const SKIP_TYPE = 'ТРАНСФЕР СОБСТВЕНИ СМЕТКИ';
const CARD_REGEX = /^\d{6}x{6}\d{4}$/;
const POS_REGEX = /^\s*ПЛАЩАНЕ\s+НА\s+ПОС\s+\d{2}\.\d{2}\.\d{4}\s+\d{2}:\d{2}/;
const COL = {
DATE: 'Дата',
TYPE: 'Вид на трансакцията',
REASON: 'Основание',
DEBIT: 'Дебит BGN',
CREDIT: 'Кредит BGN',
PAYEE: 'Наредител/Получател',
ACCT: 'Номер сметка на наредителя / получателя',
};
const TAG_RULES = [
['reason', 'ЗАПЛАТА', 'Salary'],
['reason', 'ТЕГЛЕНЕ НА ATM', 'ATM'],
['reason', 'ПЛАЩАНЕ ПО ЗАЕМ', 'Home Credit'],
['reason', 'АВТ.ТАКСА ОБСЛУЖВАНЕ', 'Bills'],
['transactionType', 'КОМУНАЛНИ УСЛУГИ', 'Bills'],
['payee', 'VIVACOM', 'Subscriptions'],
['payee', 'Google', 'Subscriptions'],
['payee', 'SkyShowtime', 'Subscriptions'],
['payee', 'NETFLIX', 'Subscriptions'],
['payee', 'LUKOIL', 'Bills'],
['payee', 'CityGate', 'Bills'],
['payee', 'CBA', 'Groceries'],
['payee', 'FANTASTICO', 'Groceries'],
['payee', 'LIDL', 'Groceries'],
];
function parseNum(val) {
if (val == null || val === '') return null;
if (typeof val === 'number') return isNaN(val) ? null : val;
const s = String(val).trim().replace(/\xa0/g, '').replace(/ /g, '').replace(',', '.');
const n = parseFloat(s);
return isNaN(n) ? null : n;
}
function parseDate(val) {
if (!val) return null;
const s = String(val).trim();
const m = s.match(/^(\d{2})\.(\d{2})\.(\d{4})$/);
if (m) {
return new Date(Date.UTC(parseInt(m[3]), parseInt(m[2]) - 1, parseInt(m[1])));
}
return null;
}
function processReasonAndCard(reason) {
if (!reason || typeof reason !== 'string') return { reason: '', card: null };
const parts = reason.trim().split(' ');
let card = null;
let cleanReason = reason.trim();
if (parts[0] && CARD_REGEX.test(parts[0])) {
card = parts[0];
cleanReason = parts.slice(1).join(' ').trim();
}
if (POS_REGEX.test(cleanReason)) {
const posParts = cleanReason.split('<br/>');
try {
const dateTime = posParts[0].split('ПОС ')[1];
cleanReason = `POS PAYMENT ${dateTime}`;
} catch (_) { /* keep original */ }
}
return { reason: cleanReason.replace(/\s+/g, ' ').trim(), card };
}
function generateTags(fields) {
const tags = new Set();
for (const [field, keyword, tagName] of TAG_RULES) {
if ((fields[field] || '').includes(keyword)) {
tags.add(tagName);
}
}
return Array.from(tags);
}
function processRow(row) {
const transactionType = (row[COL.TYPE] || '').trim();
if (transactionType === SKIP_TYPE) return null;
const { reason, card } = processReasonAndCard(row[COL.REASON]);
const payee = (row[COL.PAYEE] || '').trim();
const payerAccount = (row[COL.ACCT] || '').trim();
const debitBgn = parseNum(row[COL.DEBIT]);
const creditBgn = parseNum(row[COL.CREDIT]);
const date = parseDate(row[COL.DATE]);
const autoTags = generateTags({ reason, transactionType, payee, debitBgn, creditBgn });
const amount = debitBgn ?? creditBgn ?? null;
const rawMessage = [
row[COL.DATE] && `Date: ${row[COL.DATE]}`,
transactionType && `Type: ${transactionType}`,
payee && `Payee: ${payee}`,
debitBgn != null && `Debit: ${debitBgn} BGN`,
creditBgn != null && `Credit: ${creditBgn} BGN`,
].filter(Boolean).join(' | ');
return {
rawMessage,
date,
type: null,
card,
recipient: payee || null,
amount,
currency: 'BGN',
balance: null,
source: 'UPLOAD',
debitBgn,
creditBgn,
transactionType: transactionType || null,
payerAccount: payerAccount || null,
autoTags,
};
}
/**
* Parse a Buffer containing a DSK Bank CSV (cp1251 or UTF-8).
* Returns { rows, skipped, errors }.
*/
async function parseDskCsv(buffer) {
// Try cp1251 first (DSK Bank export encoding), fall back to UTF-8
let text = iconv.decode(buffer, 'cp1251');
if (!text.includes(COL.DATE)) {
text = buffer.toString('utf-8');
}
return new Promise((resolve, reject) => {
const rows = [];
const errors = [];
let skipped = 0;
const parser = parse(text, {
columns: true,
skip_empty_lines: true,
trim: true,
relax_column_count: true,
});
parser.on('readable', () => {
let record;
while ((record = parser.read()) !== null) {
try {
const row = processRow(record);
if (row === null) { skipped++; } else { rows.push(row); }
} catch (err) {
errors.push(err.message);
}
}
});
parser.on('error', reject);
parser.on('end', () => resolve({ rows, skipped, errors }));
});
}
module.exports = { parseDskCsv };
Write
index.js
index.js
39 lines
const express = require('express');
const cors = require('cors');
const morgan = require('morgan');
const rateLimit = require('express-rate-limit');
const { authentikMiddleware } = require('./auth');
const paymentsRouter = require('./routes/payments');
const uploadRouter = require('./routes/upload');
const app = express();
const PORT = process.env.PORT || 3001;
app.use(cors());
app.use(express.json({ limit: '16kb' }));
app.use(morgan('combined'));
// Rate-limit the public ingest endpoint before auth middleware
const ingestLimiter = rateLimit({
windowMs...
|
11868
|
NULL
|
NULL
|
NULL
|
|
13890
|
620
|
43
|
2026-05-09T16:38:31.158983+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-09/1778 /Users/lukas/.screenpipe/data/data/2026-05-09/1778344711158_m2.jpg...
|
Firefox
|
Providers - Admin - authentik — Personal
|
True
|
auth.lakylak.xyz/if/admin/#/core/providers
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Pull requests · screenpipe/screenpipe · GitHub
Clo Pull requests · screenpipe/screenpipe · GitHub
Close tab
DNS / Nameservers | Hostinger
Close tab
Nginx Proxy Manager
Close tab
Screenpipe — Archive
Close tab
SQLite Web: archive.db
Close tab
SQLite Web: db.sqlite
Close tab
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
Close tab
DXP4800PLUS-B5F8
Close tab
AFFiNE - All In One KnowledgeOS
Close tab
All docs · AFFiNE
Close tab
Payments Logger
Close tab
Your old PC can run Windows 11 in a VM, but not on bare metal - [EMAIL] - Gmail
Close tab
Location Logger
Close tab
Finance Hub
Close tab
Finance Hub
Close tab
Select: transactions - db - Adminer
Close tab
Електронно банкиране ДСК Директ от Банка ДСК
Close tab
Stop Losing Notes: Pick A Cross-Device App That Syncs | AFFiNE
Close tab
VIVACOM
Close tab
Смартфони с Unlimited план до 120 € отстъпка | Vivacom
Close tab
VIVACOM
Close tab
Смартфон SAMSUNG GALAXY A57 5G 256GB | Vivacom
Close tab
Claude Code | Claude Platform
Close tab
Claude
Close tab
lakylak/finance-hub - finance-hub - Gitea: Git with a cup of tea
Close tab
Providers - Admin - authentik
Close tab
New Tab
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Customize sidebar
Skip to content
Home
Providers
Provide support for protocols like SAML and OAuth to assigned applications.
Provide support for protocols like SAML and OAuth to assigned applications.
Toggle API requests drawer
Toggle notifications drawer
0
unread
Settings
Sign out
User interface
User interface
Dashboards
Collapse Dashboards
Dashboards
Overview
Overview
User Statistics
User Statistics
System Tasks
System Tasks
Applications
Collapse Applications
Applications
Applications
Applications
Providers
Providers
Outposts
Outposts
Endpoint Devices
Expand Endpoint Devices
Endpoint Devices
Events
Expand Events
Events
Customization
Expand Customization
Customization
Flows and Stages
Expand Flows and Stages
Flows and Stages
Directory
Expand Directory
Directory
System
Expand System
System
Enterprise
Expand Enterprise
Enterprise
Product name
authentik
Product version
Version 2026.2.1
Select all rows on page (0 of 3 selected)
Name
Sort by "Name"
Name
Application
Application
Type
Type
Row Actions
Actions
Select "Reminders Proxy" row
Reminders Proxy
Reminders Proxy
Assigned to application
Reminders
Reminders
Proxy Provider
Edit "Reminders Proxy" provider
Select "open-webui" row
open-webui
open-webui
Assigned to application
Open WebUI
Open WebUI
OAuth2/OpenID Provider
Edit "open-webui" provider
Select "reminders-mcp" row
reminders-mcp
reminders-mcp
Assigned to application
Reminders MCP
Reminders MCP
OAuth2/OpenID Provider
Edit "reminders-mcp" provider
Name
Sort by "Name"
Name
Reminders Proxy
Reminders Proxy
open-webui
open-webui
reminders-mcp
reminders-mcp
Application
Application
Assigned to application
Reminders
Reminders
Assigned to application
Open WebUI
Open WebUI
Assigned to application
Reminders MCP
Reminders MCP
Type
Type
Proxy Provider
OAuth2/OpenID Provider
OAuth2/OpenID Provider
Row Actions
Actions
Edit "Reminders Proxy" provider
Edit "open-webui" provider
Edit "reminders-mcp" provider
Last refreshed
55 seconds ago
1 - 3 of 3
1 - 3 of 3
Go to previous page
Go to next page
Close sidebar...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Pull requests · screenpipe/screenpipe · GitHub","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.016123671,"height":0.032721467},"on_screen":false,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.0006648936,"top":0.0,"width":0.004986702,"height":0.011971269},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"DNS / Nameservers | Hostinger","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.016123671,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.0006648936,"top":0.0,"width":0.004986702,"height":0.011971269},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Nginx Proxy Manager","depth":4,"bounds":{"left":0.0,"top":0.028332002,"width":0.016123671,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.0006648936,"top":0.028332002,"width":0.004986702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Screenpipe — Archive","depth":4,"bounds":{"left":0.0,"top":0.061053474,"width":0.016123671,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.0006648936,"top":0.061053474,"width":0.004986702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"SQLite Web: archive.db","depth":4,"bounds":{"left":0.0,"top":0.09377494,"width":0.016123671,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.0006648936,"top":0.09377494,"width":0.004986702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"SQLite Web: db.sqlite","depth":4,"bounds":{"left":0.0,"top":0.1264964,"width":0.016123671,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.0006648936,"top":0.1264964,"width":0.004986702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub","depth":4,"bounds":{"left":0.0,"top":0.15921788,"width":0.016123671,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.0006648936,"top":0.15921788,"width":0.004986702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"DXP4800PLUS-B5F8","depth":4,"bounds":{"left":0.0,"top":0.19193934,"width":0.016123671,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.0006648936,"top":0.19193934,"width":0.004986702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"AFFiNE - All In One KnowledgeOS","depth":4,"bounds":{"left":0.0,"top":0.22466081,"width":0.016123671,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.0006648936,"top":0.22466081,"width":0.004986702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"All docs · AFFiNE","depth":4,"bounds":{"left":0.0,"top":0.25738227,"width":0.016123671,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.0006648936,"top":0.25738227,"width":0.004986702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Payments Logger","depth":4,"bounds":{"left":0.0,"top":0.29010376,"width":0.016123671,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.0006648936,"top":0.29010376,"width":0.004986702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Your old PC can run Windows 11 in a VM, but not on bare metal - kovaliklukas@gmail.com - Gmail","depth":4,"bounds":{"left":0.0,"top":0.32282522,"width":0.016123671,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.0006648936,"top":0.32282522,"width":0.004986702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Location Logger","depth":4,"bounds":{"left":0.0,"top":0.35554668,"width":0.016123671,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.0006648936,"top":0.35554668,"width":0.004986702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Finance Hub","depth":4,"bounds":{"left":0.0,"top":0.38826814,"width":0.016123671,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.0006648936,"top":0.38826814,"width":0.004986702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Finance Hub","depth":4,"bounds":{"left":0.0,"top":0.42098963,"width":0.016123671,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.0006648936,"top":0.42098963,"width":0.004986702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Select: transactions - db - Adminer","depth":4,"bounds":{"left":0.0,"top":0.4537111,"width":0.016123671,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.0006648936,"top":0.4537111,"width":0.004986702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Електронно банкиране ДСК Директ от Банка ДСК","depth":4,"bounds":{"left":0.0,"top":0.48643255,"width":0.016123671,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.0006648936,"top":0.48643255,"width":0.004986702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Stop Losing Notes: Pick A Cross-Device App That Syncs | AFFiNE","depth":4,"bounds":{"left":0.0,"top":0.519154,"width":0.016123671,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.0006648936,"top":0.519154,"width":0.004986702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"VIVACOM","depth":4,"bounds":{"left":0.0,"top":0.5518755,"width":0.016123671,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.0006648936,"top":0.5518755,"width":0.004986702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Смартфони с Unlimited план до 120 € отстъпка | Vivacom","depth":4,"bounds":{"left":0.0,"top":0.584597,"width":0.016123671,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.0006648936,"top":0.584597,"width":0.004986702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"VIVACOM","depth":4,"bounds":{"left":0.0,"top":0.61731845,"width":0.016123671,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.0006648936,"top":0.61731845,"width":0.004986702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Смартфон SAMSUNG GALAXY A57 5G 256GB | Vivacom","depth":4,"bounds":{"left":0.0,"top":0.6500399,"width":0.016123671,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.0006648936,"top":0.6500399,"width":0.004986702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Claude Code | Claude Platform","depth":4,"bounds":{"left":0.0,"top":0.6827614,"width":0.016123671,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.0006648936,"top":0.6827614,"width":0.004986702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Claude","depth":4,"bounds":{"left":0.0,"top":0.71548283,"width":0.016123671,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.0006648936,"top":0.71548283,"width":0.004986702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"lakylak/finance-hub - finance-hub - Gitea: Git with a cup of tea","depth":4,"bounds":{"left":0.0,"top":0.7482043,"width":0.016123671,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.0006648936,"top":0.7482043,"width":0.004986702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Providers - Admin - authentik","depth":4,"bounds":{"left":0.0,"top":0.78092575,"width":0.016123671,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.0006648936,"top":0.78092575,"width":0.004986702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.0028257978,"top":0.81803674,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"bounds":{"left":0.0,"top":0.8547486,"width":0.016123671,"height":0.0311253},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.0,"top":0.8858739,"width":0.016123671,"height":0.027533919},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.0,"top":0.9134078,"width":0.016123671,"height":0.02793296},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bitwarden","depth":6,"bounds":{"left":0.0,"top":0.9413408,"width":0.016123671,"height":0.027533919},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.0,"top":0.9688747,"width":0.016123671,"height":0.0311253},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Skip to content","depth":6,"bounds":{"left":0.016123671,"top":0.0518755,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Home","depth":8,"bounds":{"left":0.025099734,"top":0.08539505,"width":0.078457445,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Providers","depth":10,"bounds":{"left":0.13547207,"top":0.075019956,"width":0.03474069,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Provide support for protocols like SAML and OAuth to assigned applications.","depth":8,"bounds":{"left":0.123171546,"top":0.1009577,"width":0.2330452,"height":0.033519555},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Provide support for protocols like SAML and OAuth to assigned applications.","depth":10,"bounds":{"left":0.123171546,"top":0.10574621,"width":0.18018617,"height":0.01715882},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle API requests drawer","depth":10,"bounds":{"left":0.3615359,"top":0.08539505,"width":0.017287234,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Toggle notifications drawer","depth":10,"bounds":{"left":0.37882313,"top":0.08539505,"width":0.02144282,"height":0.028731046},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"0","depth":13,"bounds":{"left":0.39145613,"top":0.09098165,"width":0.0034906915,"height":0.01715882},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"unread","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Settings","depth":10,"bounds":{"left":0.40026596,"top":0.08539505,"width":0.015957447,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Sign out","depth":10,"bounds":{"left":0.4162234,"top":0.08539505,"width":0.015957447,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"User interface","depth":9,"bounds":{"left":0.43218085,"top":0.086592175,"width":0.039893616,"height":0.026336791},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"User interface","depth":10,"bounds":{"left":0.4375,"top":0.09217877,"width":0.02925532,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Dashboards","depth":8,"bounds":{"left":0.017121011,"top":0.15403032,"width":0.09541223,"height":0.1300878},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXButton","text":"Collapse Dashboards","depth":9,"bounds":{"left":0.017121011,"top":0.15403032,"width":0.09541223,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXStaticText","text":"Dashboards","depth":10,"bounds":{"left":0.02244016,"top":0.16161214,"width":0.02825798,"height":0.01715882},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Overview","depth":12,"bounds":{"left":0.023603724,"top":0.18914606,"width":0.08892952,"height":0.02952913},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Overview","depth":13,"bounds":{"left":0.028922873,"top":0.1963288,"width":0.019448139,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"User Statistics","depth":12,"bounds":{"left":0.023603724,"top":0.21867518,"width":0.08892952,"height":0.02952913},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"User Statistics","depth":13,"bounds":{"left":0.028922873,"top":0.22585794,"width":0.029920213,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"System Tasks","depth":12,"bounds":{"left":0.023603724,"top":0.2482043,"width":0.08892952,"height":0.02952913},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"System Tasks","depth":13,"bounds":{"left":0.028922873,"top":0.25538707,"width":0.027759308,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Applications","depth":8,"bounds":{"left":0.017121011,"top":0.28411812,"width":0.09541223,"height":0.1300878},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXButton","text":"Collapse Applications","depth":9,"bounds":{"left":0.017121011,"top":0.28411812,"width":0.09541223,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXStaticText","text":"Applications","depth":10,"bounds":{"left":0.02244016,"top":0.29169992,"width":0.02925532,"height":0.01715882},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Applications","depth":12,"bounds":{"left":0.023603724,"top":0.31923383,"width":0.08892952,"height":0.02952913},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Applications","depth":13,"bounds":{"left":0.028922873,"top":0.3264166,"width":0.02543218,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Providers","depth":12,"bounds":{"left":0.023603724,"top":0.34876296,"width":0.08892952,"height":0.02952913},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Providers","depth":13,"bounds":{"left":0.028922873,"top":0.35594574,"width":0.019448139,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Outposts","depth":12,"bounds":{"left":0.023603724,"top":0.3782921,"width":0.08892952,"height":0.02952913},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Outposts","depth":13,"bounds":{"left":0.028922873,"top":0.38547486,"width":0.019448139,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Endpoint Devices","depth":8,"bounds":{"left":0.017121011,"top":0.4142059,"width":0.09541223,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXButton","text":"Expand Endpoint Devices","depth":9,"bounds":{"left":0.017121011,"top":0.4142059,"width":0.09541223,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Endpoint Devices","depth":10,"bounds":{"left":0.02244016,"top":0.4217877,"width":0.04155585,"height":0.01715882},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Events","depth":8,"bounds":{"left":0.017121011,"top":0.44932163,"width":0.09541223,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXButton","text":"Expand Events","depth":9,"bounds":{"left":0.017121011,"top":0.44932163,"width":0.09541223,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Events","depth":10,"bounds":{"left":0.02244016,"top":0.45690343,"width":0.016123671,"height":0.01715882},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Customization","depth":8,"bounds":{"left":0.017121011,"top":0.48443735,"width":0.09541223,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXButton","text":"Expand Customization","depth":9,"bounds":{"left":0.017121011,"top":0.48443735,"width":0.09541223,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Customization","depth":10,"bounds":{"left":0.02244016,"top":0.49201915,"width":0.034242023,"height":0.01715882},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Flows and Stages","depth":8,"bounds":{"left":0.017121011,"top":0.51955307,"width":0.09541223,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXButton","text":"Expand Flows and Stages","depth":9,"bounds":{"left":0.017121011,"top":0.51955307,"width":0.09541223,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Flows and Stages","depth":10,"bounds":{"left":0.02244016,"top":0.5271349,"width":0.04138963,"height":0.01715882},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Directory","depth":8,"bounds":{"left":0.017121011,"top":0.5546688,"width":0.09541223,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXButton","text":"Expand Directory","depth":9,"bounds":{"left":0.017121011,"top":0.5546688,"width":0.09541223,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Directory","depth":10,"bounds":{"left":0.02244016,"top":0.5622506,"width":0.022107713,"height":0.01715882},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"System","depth":8,"bounds":{"left":0.017121011,"top":0.5897845,"width":0.09541223,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXButton","text":"Expand System","depth":9,"bounds":{"left":0.017121011,"top":0.5897845,"width":0.09541223,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"System","depth":10,"bounds":{"left":0.02244016,"top":0.59736633,"width":0.017785905,"height":0.01715882},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Enterprise","depth":8,"bounds":{"left":0.017121011,"top":0.6249002,"width":0.09541223,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXButton","text":"Expand Enterprise","depth":9,"bounds":{"left":0.017121011,"top":0.6249002,"width":0.09541223,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Enterprise","depth":10,"bounds":{"left":0.02244016,"top":0.63248205,"width":0.024601065,"height":0.01715882},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Product name","depth":8,"bounds":{"left":0.026761968,"top":0.9537111,"width":0.07513298,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"authentik","depth":9,"bounds":{"left":0.056017287,"top":0.9545092,"width":0.01662234,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Product version","depth":8,"bounds":{"left":0.026761968,"top":0.9680766,"width":0.07513298,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Version 2026.2.1","depth":9,"bounds":{"left":0.050033245,"top":0.9688747,"width":0.028590426,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Select all rows on page (0 of 3 selected)","depth":14,"bounds":{"left":0.12849069,"top":0.23463687,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCell","text":"Name","depth":13,"bounds":{"left":0.13646941,"top":0.22106944,"width":0.06582447,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"cell","subrole":"AXUnknown"},{"role":"AXButton","text":"Sort by \"Name\"","depth":14,"bounds":{"left":0.13646941,"top":0.22825219,"width":0.026263298,"height":0.026336791},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Name","depth":16,"bounds":{"left":0.13912898,"top":0.23383878,"width":0.013297873,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCell","text":"Application","depth":13,"bounds":{"left":0.20229389,"top":0.22106944,"width":0.15442154,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"cell","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Application","depth":14,"bounds":{"left":0.20495346,"top":0.23383878,"width":0.026097074,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCell","text":"Type","depth":13,"bounds":{"left":0.3567154,"top":0.22106944,"width":0.09541223,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"cell","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Type","depth":14,"bounds":{"left":0.359375,"top":0.23383878,"width":0.011136968,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCell","text":"Row Actions","depth":13,"bounds":{"left":0.45212767,"top":0.22106944,"width":0.039893616,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"cell","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Actions","depth":14,"bounds":{"left":0.45478722,"top":0.23383878,"width":0.017287234,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Select \"Reminders Proxy\" row","depth":13,"bounds":{"left":0.12849069,"top":0.27214685,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Reminders Proxy","depth":13,"bounds":{"left":0.13912898,"top":0.27094972,"width":0.03474069,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Reminders Proxy","depth":14,"bounds":{"left":0.13912898,"top":0.27094972,"width":0.03474069,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Assigned to application","depth":13,"bounds":{"left":0.21060506,"top":0.27094972,"width":0.049534574,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Reminders","depth":13,"bounds":{"left":0.2601396,"top":0.27094972,"width":0.021941489,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Reminders","depth":14,"bounds":{"left":0.2601396,"top":0.27094972,"width":0.021941489,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Proxy Provider","depth":13,"bounds":{"left":0.359375,"top":0.27094972,"width":0.030086435,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Edit \"Reminders Proxy\" provider","depth":14,"bounds":{"left":0.45478722,"top":0.26336792,"width":0.011303191,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Select \"open-webui\" row","depth":13,"bounds":{"left":0.12849069,"top":0.31444532,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"open-webui","depth":13,"bounds":{"left":0.13912898,"top":0.31324822,"width":0.024767287,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"open-webui","depth":14,"bounds":{"left":0.13912898,"top":0.31324822,"width":0.024767287,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Assigned to application","depth":13,"bounds":{"left":0.21060506,"top":0.31324822,"width":0.049534574,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Open WebUI","depth":13,"bounds":{"left":0.2601396,"top":0.31324822,"width":0.02642952,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Open WebUI","depth":14,"bounds":{"left":0.2601396,"top":0.31324822,"width":0.02642952,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"OAuth2/OpenID Provider","depth":13,"bounds":{"left":0.359375,"top":0.31324822,"width":0.05285904,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Edit \"open-webui\" provider","depth":14,"bounds":{"left":0.45478722,"top":0.3056664,"width":0.011303191,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Select \"reminders-mcp\" row","depth":13,"bounds":{"left":0.12849069,"top":0.3567438,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"reminders-mcp","depth":13,"bounds":{"left":0.13912898,"top":0.35554668,"width":0.03174867,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"reminders-mcp","depth":14,"bounds":{"left":0.13912898,"top":0.35554668,"width":0.03174867,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Assigned to application","depth":13,"bounds":{"left":0.21060506,"top":0.35554668,"width":0.049534574,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Reminders MCP","depth":13,"bounds":{"left":0.2601396,"top":0.35554668,"width":0.033410903,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Reminders MCP","depth":14,"bounds":{"left":0.2601396,"top":0.35554668,"width":0.033410903,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"OAuth2/OpenID Provider","depth":13,"bounds":{"left":0.359375,"top":0.35554668,"width":0.05285904,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Edit \"reminders-mcp\" provider","depth":14,"bounds":{"left":0.45478722,"top":0.34796488,"width":0.011303191,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCell","text":"Name","depth":12,"bounds":{"left":0.13646941,"top":0.22106944,"width":0.06582447,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"cell","subrole":"AXUnknown"},{"role":"AXButton","text":"Sort by \"Name\"","depth":13,"bounds":{"left":0.13646941,"top":0.22825219,"width":0.026263298,"height":0.026336791},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Name","depth":15,"bounds":{"left":0.13912898,"top":0.23383878,"width":0.013297873,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Reminders Proxy","depth":13,"bounds":{"left":0.13912898,"top":0.27094972,"width":0.03474069,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Reminders Proxy","depth":14,"bounds":{"left":0.13912898,"top":0.27094972,"width":0.03474069,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"open-webui","depth":13,"bounds":{"left":0.13912898,"top":0.31324822,"width":0.024767287,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"open-webui","depth":14,"bounds":{"left":0.13912898,"top":0.31324822,"width":0.024767287,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"reminders-mcp","depth":13,"bounds":{"left":0.13912898,"top":0.35554668,"width":0.03174867,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"reminders-mcp","depth":14,"bounds":{"left":0.13912898,"top":0.35554668,"width":0.03174867,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCell","text":"Application","depth":12,"bounds":{"left":0.20229389,"top":0.22106944,"width":0.15442154,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"cell","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Application","depth":13,"bounds":{"left":0.20495346,"top":0.23383878,"width":0.026097074,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Assigned to application","depth":13,"bounds":{"left":0.21060506,"top":0.27094972,"width":0.049534574,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Reminders","depth":13,"bounds":{"left":0.2601396,"top":0.27094972,"width":0.021941489,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Reminders","depth":14,"bounds":{"left":0.2601396,"top":0.27094972,"width":0.021941489,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Assigned to application","depth":13,"bounds":{"left":0.21060506,"top":0.31324822,"width":0.049534574,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Open WebUI","depth":13,"bounds":{"left":0.2601396,"top":0.31324822,"width":0.02642952,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Open WebUI","depth":14,"bounds":{"left":0.2601396,"top":0.31324822,"width":0.02642952,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Assigned to application","depth":13,"bounds":{"left":0.21060506,"top":0.35554668,"width":0.049534574,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Reminders MCP","depth":13,"bounds":{"left":0.2601396,"top":0.35554668,"width":0.033410903,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Reminders MCP","depth":14,"bounds":{"left":0.2601396,"top":0.35554668,"width":0.033410903,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCell","text":"Type","depth":12,"bounds":{"left":0.3567154,"top":0.22106944,"width":0.09541223,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"cell","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Type","depth":13,"bounds":{"left":0.359375,"top":0.23383878,"width":0.011136968,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Proxy Provider","depth":13,"bounds":{"left":0.359375,"top":0.27094972,"width":0.030086435,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"OAuth2/OpenID Provider","depth":13,"bounds":{"left":0.359375,"top":0.31324822,"width":0.05285904,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"OAuth2/OpenID Provider","depth":13,"bounds":{"left":0.359375,"top":0.35554668,"width":0.05285904,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCell","text":"Row Actions","depth":12,"bounds":{"left":0.45212767,"top":0.22106944,"width":0.039893616,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"cell","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Actions","depth":13,"bounds":{"left":0.45478722,"top":0.23383878,"width":0.017287234,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Edit \"Reminders Proxy\" provider","depth":14,"bounds":{"left":0.45478722,"top":0.26336792,"width":0.011303191,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Edit \"open-webui\" provider","depth":14,"bounds":{"left":0.45478722,"top":0.3056664,"width":0.011303191,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Edit \"reminders-mcp\" provider","depth":14,"bounds":{"left":0.45478722,"top":0.34796488,"width":0.011303191,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Last refreshed","depth":13,"bounds":{"left":0.12849069,"top":0.4046289,"width":0.025265958,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"55 seconds ago","depth":13,"bounds":{"left":0.15475398,"top":0.4046289,"width":0.027094414,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"1 - 3 of 3","depth":13,"bounds":{"left":0.4424867,"top":0.40343177,"width":0.01761968,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1 - 3 of 3","depth":14,"bounds":{"left":0.4424867,"top":0.40343177,"width":0.01761968,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Go to previous page","depth":13,"bounds":{"left":0.46276596,"top":0.39664805,"width":0.007978723,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Go to next page","depth":13,"bounds":{"left":0.47606382,"top":0.39664805,"width":0.007978723,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close sidebar","depth":6,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false}]...
|
8021209154664798841
|
-5042043145085545333
|
visual_change
|
accessibility
|
NULL
|
Pull requests · screenpipe/screenpipe · GitHub
Clo Pull requests · screenpipe/screenpipe · GitHub
Close tab
DNS / Nameservers | Hostinger
Close tab
Nginx Proxy Manager
Close tab
Screenpipe — Archive
Close tab
SQLite Web: archive.db
Close tab
SQLite Web: db.sqlite
Close tab
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
Close tab
DXP4800PLUS-B5F8
Close tab
AFFiNE - All In One KnowledgeOS
Close tab
All docs · AFFiNE
Close tab
Payments Logger
Close tab
Your old PC can run Windows 11 in a VM, but not on bare metal - [EMAIL] - Gmail
Close tab
Location Logger
Close tab
Finance Hub
Close tab
Finance Hub
Close tab
Select: transactions - db - Adminer
Close tab
Електронно банкиране ДСК Директ от Банка ДСК
Close tab
Stop Losing Notes: Pick A Cross-Device App That Syncs | AFFiNE
Close tab
VIVACOM
Close tab
Смартфони с Unlimited план до 120 € отстъпка | Vivacom
Close tab
VIVACOM
Close tab
Смартфон SAMSUNG GALAXY A57 5G 256GB | Vivacom
Close tab
Claude Code | Claude Platform
Close tab
Claude
Close tab
lakylak/finance-hub - finance-hub - Gitea: Git with a cup of tea
Close tab
Providers - Admin - authentik
Close tab
New Tab
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Customize sidebar
Skip to content
Home
Providers
Provide support for protocols like SAML and OAuth to assigned applications.
Provide support for protocols like SAML and OAuth to assigned applications.
Toggle API requests drawer
Toggle notifications drawer
0
unread
Settings
Sign out
User interface
User interface
Dashboards
Collapse Dashboards
Dashboards
Overview
Overview
User Statistics
User Statistics
System Tasks
System Tasks
Applications
Collapse Applications
Applications
Applications
Applications
Providers
Providers
Outposts
Outposts
Endpoint Devices
Expand Endpoint Devices
Endpoint Devices
Events
Expand Events
Events
Customization
Expand Customization
Customization
Flows and Stages
Expand Flows and Stages
Flows and Stages
Directory
Expand Directory
Directory
System
Expand System
System
Enterprise
Expand Enterprise
Enterprise
Product name
authentik
Product version
Version 2026.2.1
Select all rows on page (0 of 3 selected)
Name
Sort by "Name"
Name
Application
Application
Type
Type
Row Actions
Actions
Select "Reminders Proxy" row
Reminders Proxy
Reminders Proxy
Assigned to application
Reminders
Reminders
Proxy Provider
Edit "Reminders Proxy" provider
Select "open-webui" row
open-webui
open-webui
Assigned to application
Open WebUI
Open WebUI
OAuth2/OpenID Provider
Edit "open-webui" provider
Select "reminders-mcp" row
reminders-mcp
reminders-mcp
Assigned to application
Reminders MCP
Reminders MCP
OAuth2/OpenID Provider
Edit "reminders-mcp" provider
Name
Sort by "Name"
Name
Reminders Proxy
Reminders Proxy
open-webui
open-webui
reminders-mcp
reminders-mcp
Application
Application
Assigned to application
Reminders
Reminders
Assigned to application
Open WebUI
Open WebUI
Assigned to application
Reminders MCP
Reminders MCP
Type
Type
Proxy Provider
OAuth2/OpenID Provider
OAuth2/OpenID Provider
Row Actions
Actions
Edit "Reminders Proxy" provider
Edit "open-webui" provider
Edit "reminders-mcp" provider
Last refreshed
55 seconds ago
1 - 3 of 3
1 - 3 of 3
Go to previous page
Go to next page
Close sidebar...
|
13889
|
NULL
|
NULL
|
NULL
|
|
13901
|
619
|
43
|
2026-05-09T16:39:17.423938+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-09/1778 /Users/lukas/.screenpipe/data/data/2026-05-09/1778344757423_m1.jpg...
|
Firefox
|
Providers - Admin - authentik — Personal
|
True
|
auth.lakylak.xyz/if/admin/#/core/providers
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Pull requests · screenpipe/screenpipe · GitHub
Clo Pull requests · screenpipe/screenpipe · GitHub
Close tab
DNS / Nameservers | Hostinger
Close tab
Nginx Proxy Manager
Close tab
Screenpipe — Archive
Close tab
SQLite Web: archive.db
Close tab
SQLite Web: db.sqlite
Close tab
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
Close tab
DXP4800PLUS-B5F8
Close tab
AFFiNE - All In One KnowledgeOS
Close tab
All docs · AFFiNE
Close tab
Payments Logger
Close tab
Your old PC can run Windows 11 in a VM, but not on bare metal - [EMAIL] - Gmail
Close tab
Location Logger
Close tab
Finance Hub
Close tab
Finance Hub
Close tab
Select: transactions - db - Adminer
Close tab
Електронно банкиране ДСК Директ от Банка ДСК
Close tab
Stop Losing Notes: Pick A Cross-Device App That Syncs | AFFiNE
Close tab
VIVACOM
Close tab
Смартфони с Unlimited план до 120 € отстъпка | Vivacom
Close tab
VIVACOM
Close tab
Смартфон SAMSUNG GALAXY A57 5G 256GB | Vivacom
Close tab
Claude Code | Claude Platform
Close tab
Claude
Close tab
lakylak/finance-hub - finance-hub - Gitea: Git with a cup of tea
Close tab
Providers - Admin - authentik
Close tab
New Tab
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Customize sidebar
Skip to content
Home
Providers
Provide support for protocols like SAML and OAuth to assigned applications.
Provide support for protocols like SAML and OAuth to assigned applications.
Toggle API requests drawer
Toggle notifications drawer
0
unread
Settings
Sign out
User interface
User interface
Dashboards
Collapse Dashboards
Dashboards
Overview
Overview
User Statistics
User Statistics
System Tasks
System Tasks
Applications
Collapse Applications
Applications
Applications
Applications
Providers
Providers
Outposts
Outposts
Endpoint Devices
Expand Endpoint Devices
Endpoint Devices
Events
Expand Events
Events
Customization
Expand Customization
Customization
Flows and Stages
Expand Flows and Stages
Flows and Stages
Directory
Expand Directory
Directory
System
Expand System
System
Enterprise
Expand Enterprise
Enterprise
Product name
authentik
Product version
Version 2026.2.1
Select all rows on page (0 of 4 selected)
Name
Sort by "Name"
Name
Application
Application
Type
Type
Row Actions
Actions
Select "Finance Hub Proxy" row
Finance Hub Proxy
Finance Hub Proxy
Provider not assigned to any application.
Proxy Provider
Edit "Finance Hub Proxy" provider
Select "Reminders Proxy" row
Reminders Proxy
Reminders Proxy
Assigned to application
Reminders
Reminders
Proxy Provider
Edit "Reminders Proxy" provider
Select "open-webui" row
open-webui
open-webui
Assigned to application
Open WebUI
Open WebUI
OAuth2/OpenID Provider
Edit "open-webui" provider
Select "reminders-mcp" row
reminders-mcp
reminders-mcp
Assigned to application
Reminders MCP
Reminders MCP
OAuth2/OpenID Provider
Edit "reminders-mcp" provider
Name
Sort by "Name"
Name
Finance Hub Proxy
Finance Hub Proxy
Reminders Proxy
Reminders Proxy
open-webui
open-webui
reminders-mcp
reminders-mcp
Application
Application
Provider not assigned to any application.
Assigned to application
Reminders
Reminders
Assigned to application
Open WebUI
Open WebUI
Assigned to application
Reminders MCP
Reminders MCP
Type
Type
Proxy Provider
Proxy Provider
OAuth2/OpenID Provider
OAuth2/OpenID Provider
Row Actions
Actions
Edit "Finance Hub Proxy" provider
Edit "Reminders Proxy" provider
Edit "open-webui" provider
Edit "reminders-mcp" provider
Last refreshed
8 seconds ago
1 - 4 of 4
1 - 4 of 4
Go to previous page
Go to next page
Close sidebar
auth.lakylak.xyz/if/admin/#/core/applications...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Pull requests · screenpipe/screenpipe · GitHub","depth":4,"on_screen":false,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"DNS / Nameservers | Hostinger","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Nginx Proxy Manager","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Screenpipe — Archive","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"SQLite Web: archive.db","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"SQLite Web: db.sqlite","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"DXP4800PLUS-B5F8","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"AFFiNE - All In One KnowledgeOS","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"All docs · AFFiNE","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Payments Logger","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Your old PC can run Windows 11 in a VM, but not on bare metal - kovaliklukas@gmail.com - Gmail","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Location Logger","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Finance Hub","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Finance Hub","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Select: transactions - db - Adminer","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Електронно банкиране ДСК Директ от Банка ДСК","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Stop Losing Notes: Pick A Cross-Device App That Syncs | AFFiNE","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"VIVACOM","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Смартфони с Unlimited план до 120 € отстъпка | Vivacom","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"VIVACOM","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Смартфон SAMSUNG GALAXY A57 5G 256GB | Vivacom","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Claude Code | Claude Platform","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Claude","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"lakylak/finance-hub - finance-hub - Gitea: Git with a cup of tea","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Providers - Admin - authentik","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bitwarden","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Skip to content","depth":6,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Home","depth":8,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Providers","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Provide support for protocols like SAML and OAuth to assigned applications.","depth":8,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Provide support for protocols like SAML and OAuth to assigned applications.","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle API requests drawer","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Toggle notifications drawer","depth":10,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"0","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"unread","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Settings","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Sign out","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"User interface","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"User interface","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Dashboards","depth":8,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXButton","text":"Collapse Dashboards","depth":9,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXStaticText","text":"Dashboards","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Overview","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Overview","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"User Statistics","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"User Statistics","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"System Tasks","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"System Tasks","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Applications","depth":8,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXButton","text":"Collapse Applications","depth":9,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXStaticText","text":"Applications","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Applications","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":true,"is_selected":false},{"role":"AXStaticText","text":"Applications","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Providers","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Providers","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Outposts","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Outposts","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Endpoint Devices","depth":8,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXButton","text":"Expand Endpoint Devices","depth":9,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Endpoint Devices","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Events","depth":8,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXButton","text":"Expand Events","depth":9,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Events","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Customization","depth":8,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXButton","text":"Expand Customization","depth":9,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Customization","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Flows and Stages","depth":8,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXButton","text":"Expand Flows and Stages","depth":9,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Flows and Stages","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Directory","depth":8,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXButton","text":"Expand Directory","depth":9,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Directory","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"System","depth":8,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXButton","text":"Expand System","depth":9,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"System","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Enterprise","depth":8,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXButton","text":"Expand Enterprise","depth":9,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Enterprise","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Product name","depth":8,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"authentik","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Product version","depth":8,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Version 2026.2.1","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Select all rows on page (0 of 4 selected)","depth":14,"on_screen":true,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCell","text":"Name","depth":13,"on_screen":true,"help_text":"","role_description":"cell","subrole":"AXUnknown"},{"role":"AXButton","text":"Sort by \"Name\"","depth":14,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Name","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCell","text":"Application","depth":13,"on_screen":true,"help_text":"","role_description":"cell","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Application","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCell","text":"Type","depth":13,"on_screen":true,"help_text":"","role_description":"cell","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Type","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCell","text":"Row Actions","depth":13,"on_screen":true,"help_text":"","role_description":"cell","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Actions","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Select \"Finance Hub Proxy\" row","depth":13,"on_screen":true,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Finance Hub Proxy","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Finance Hub Proxy","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Provider not assigned to any application.","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Proxy Provider","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Edit \"Finance Hub Proxy\" provider","depth":14,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Select \"Reminders Proxy\" row","depth":13,"on_screen":true,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Reminders Proxy","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Reminders Proxy","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Assigned to application","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Reminders","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Reminders","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Proxy Provider","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Edit \"Reminders Proxy\" provider","depth":14,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Select \"open-webui\" row","depth":13,"on_screen":true,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"open-webui","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"open-webui","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Assigned to application","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Open WebUI","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Open WebUI","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"OAuth2/OpenID Provider","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Edit \"open-webui\" provider","depth":14,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Select \"reminders-mcp\" row","depth":13,"on_screen":true,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"reminders-mcp","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"reminders-mcp","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Assigned to application","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Reminders MCP","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Reminders MCP","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"OAuth2/OpenID Provider","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Edit \"reminders-mcp\" provider","depth":14,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCell","text":"Name","depth":12,"on_screen":true,"help_text":"","role_description":"cell","subrole":"AXUnknown"},{"role":"AXButton","text":"Sort by \"Name\"","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Name","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Finance Hub Proxy","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Finance Hub Proxy","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Reminders Proxy","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Reminders Proxy","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"open-webui","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"open-webui","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"reminders-mcp","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"reminders-mcp","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCell","text":"Application","depth":12,"on_screen":true,"help_text":"","role_description":"cell","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Application","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Provider not assigned to any application.","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Assigned to application","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Reminders","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Reminders","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Assigned to application","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Open WebUI","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Open WebUI","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Assigned to application","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Reminders MCP","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Reminders MCP","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCell","text":"Type","depth":12,"on_screen":true,"help_text":"","role_description":"cell","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Type","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Proxy Provider","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Proxy Provider","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"OAuth2/OpenID Provider","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"OAuth2/OpenID Provider","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCell","text":"Row Actions","depth":12,"on_screen":true,"help_text":"","role_description":"cell","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Actions","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Edit \"Finance Hub Proxy\" provider","depth":14,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Edit \"Reminders Proxy\" provider","depth":14,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Edit \"open-webui\" provider","depth":14,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Edit \"reminders-mcp\" provider","depth":14,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Last refreshed","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"8 seconds ago","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"1 - 4 of 4","depth":13,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1 - 4 of 4","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Go to previous page","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Go to next page","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close sidebar","depth":6,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"auth.lakylak.xyz/if/admin/#/core/applications","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-4321926690155704873
|
-5023973771011648373
|
click
|
accessibility
|
NULL
|
Pull requests · screenpipe/screenpipe · GitHub
Clo Pull requests · screenpipe/screenpipe · GitHub
Close tab
DNS / Nameservers | Hostinger
Close tab
Nginx Proxy Manager
Close tab
Screenpipe — Archive
Close tab
SQLite Web: archive.db
Close tab
SQLite Web: db.sqlite
Close tab
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
Close tab
DXP4800PLUS-B5F8
Close tab
AFFiNE - All In One KnowledgeOS
Close tab
All docs · AFFiNE
Close tab
Payments Logger
Close tab
Your old PC can run Windows 11 in a VM, but not on bare metal - [EMAIL] - Gmail
Close tab
Location Logger
Close tab
Finance Hub
Close tab
Finance Hub
Close tab
Select: transactions - db - Adminer
Close tab
Електронно банкиране ДСК Директ от Банка ДСК
Close tab
Stop Losing Notes: Pick A Cross-Device App That Syncs | AFFiNE
Close tab
VIVACOM
Close tab
Смартфони с Unlimited план до 120 € отстъпка | Vivacom
Close tab
VIVACOM
Close tab
Смартфон SAMSUNG GALAXY A57 5G 256GB | Vivacom
Close tab
Claude Code | Claude Platform
Close tab
Claude
Close tab
lakylak/finance-hub - finance-hub - Gitea: Git with a cup of tea
Close tab
Providers - Admin - authentik
Close tab
New Tab
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Customize sidebar
Skip to content
Home
Providers
Provide support for protocols like SAML and OAuth to assigned applications.
Provide support for protocols like SAML and OAuth to assigned applications.
Toggle API requests drawer
Toggle notifications drawer
0
unread
Settings
Sign out
User interface
User interface
Dashboards
Collapse Dashboards
Dashboards
Overview
Overview
User Statistics
User Statistics
System Tasks
System Tasks
Applications
Collapse Applications
Applications
Applications
Applications
Providers
Providers
Outposts
Outposts
Endpoint Devices
Expand Endpoint Devices
Endpoint Devices
Events
Expand Events
Events
Customization
Expand Customization
Customization
Flows and Stages
Expand Flows and Stages
Flows and Stages
Directory
Expand Directory
Directory
System
Expand System
System
Enterprise
Expand Enterprise
Enterprise
Product name
authentik
Product version
Version 2026.2.1
Select all rows on page (0 of 4 selected)
Name
Sort by "Name"
Name
Application
Application
Type
Type
Row Actions
Actions
Select "Finance Hub Proxy" row
Finance Hub Proxy
Finance Hub Proxy
Provider not assigned to any application.
Proxy Provider
Edit "Finance Hub Proxy" provider
Select "Reminders Proxy" row
Reminders Proxy
Reminders Proxy
Assigned to application
Reminders
Reminders
Proxy Provider
Edit "Reminders Proxy" provider
Select "open-webui" row
open-webui
open-webui
Assigned to application
Open WebUI
Open WebUI
OAuth2/OpenID Provider
Edit "open-webui" provider
Select "reminders-mcp" row
reminders-mcp
reminders-mcp
Assigned to application
Reminders MCP
Reminders MCP
OAuth2/OpenID Provider
Edit "reminders-mcp" provider
Name
Sort by "Name"
Name
Finance Hub Proxy
Finance Hub Proxy
Reminders Proxy
Reminders Proxy
open-webui
open-webui
reminders-mcp
reminders-mcp
Application
Application
Provider not assigned to any application.
Assigned to application
Reminders
Reminders
Assigned to application
Open WebUI
Open WebUI
Assigned to application
Reminders MCP
Reminders MCP
Type
Type
Proxy Provider
Proxy Provider
OAuth2/OpenID Provider
OAuth2/OpenID Provider
Row Actions
Actions
Edit "Finance Hub Proxy" provider
Edit "Reminders Proxy" provider
Edit "open-webui" provider
Edit "reminders-mcp" provider
Last refreshed
8 seconds ago
1 - 4 of 4
1 - 4 of 4
Go to previous page
Go to next page
Close sidebar
auth.lakylak.xyz/if/admin/#/core/applications...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
14189
|
630
|
43
|
2026-05-09T17:03:51.830855+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-09/1778 /Users/lukas/.screenpipe/data/data/2026-05-09/1778346231830_m2.jpg...
|
Firefox
|
Nginx Proxy Manager — Personal
|
True
|
http://192.168.0.242:81/nginx/proxy
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Pull requests · screenpipe/screenpipe · GitHub
Clo Pull requests · screenpipe/screenpipe · GitHub
Close tab
DNS / Nameservers | Hostinger
Close tab
Nginx Proxy Manager
Close tab
Screenpipe — Archive
Close tab
SQLite Web: archive.db
Close tab
SQLite Web: db.sqlite
Close tab
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
Close tab
DXP4800PLUS-B5F8
Close tab
AFFiNE - All In One KnowledgeOS
Close tab
All docs · AFFiNE
Close tab
Payments Logger
Close tab
Your old PC can run Windows 11 in a VM, but not on bare metal - [EMAIL] - Gmail
Close tab
Location Logger
Close tab
Finance Hub
Close tab
Finance Hub
Close tab
Select: transactions - db - Adminer
Close tab
Claude Code | Claude Platform
Close tab
Claude
Close tab
lakylak/finance-hub - finance-hub - Gitea: Git with a cup of tea
Close tab
Applications - Admin - authentik
Close tab
New Tab
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Customize sidebar
Nginx Proxy Manager
Nginx Proxy Manager
Admin Administrator
Admin
Administrator
Dashboard
Dashboard
Hosts
Hosts
Access Lists
Access Lists
SSL Certificates
SSL Certificates
Users
Users
Audit Log
Audit Log
Settings
Settings
Proxy Hosts
Proxy Hosts
Search Host…
Add Proxy Host
Add Proxy Host
SOURCE
DESTINATION
SSL
ACCESS
STATUS
ai.chat.lakylak.xyz
Created: 10th March 2026
http://[IP_ADDRESS]:11000
Let's Encrypt
Public
Online
app.lakylak.xyz
Created: 19th July 2025
http://[IP_ADDRESS]:18083
Let's Encrypt
Public
Online
app.payments.lakylak.xyz
Created: 14th February 2026
http://[IP_ADDRESS]:5174
Let's Encrypt
Public
Online
app.screenpipe.lakylak.xyz
Created: 27th April 2026
http://[IP_ADDRESS]:8766
Let's Encrypt
Public
Online
audiobook.lakylak.xyz
Created: 15th June 2025
http://192.168..242:13378
Let's Encrypt
Public
Online
auth.lakylak.xyz
Created: 30th March 2026
http://[IP_ADDRESS]:9100
Let's Encrypt
Public
Online
backup.lakylak.xyz
Created: 10th July 2025
http://[IP_ADDRESS]:9999
Let's Encrypt
Public
Online
beszel.lakylak.xyz
Created: 6th December 2025
http://[IP_ADDRESS]:8095
Let's Encrypt
Public
Online
bitwarden.lakylak.xyz
Created: 16th June 2025
http://[IP_ADDRESS]:9890
Let's Encrypt
Public
Online
book.lakylak.xyz
Created: 31st October 2025
http://[IP_ADDRESS]:6060
Let's Encrypt
Public
Online
crm.lakylak.xyz
Created: 25th July 2025
http://[IP_ADDRESS]:3353
Let's Encrypt
Public
Online
dawarich.lakylak.xyz
Created: 25th August 2025
http://[IP_ADDRESS]:3000
Let's Encrypt
Public
Online
db.screenpipe.lakylak.xyz
Created: 27th April 2026
http://[IP_ADDRESS]:8767
Let's Encrypt
Public
Online
dsk-uploader.lakylak.xyz
Created: 15th August 2025
http://[IP_ADDRESS]:8502
Let's Encrypt
Public
Online
finance-hub.lakylak.xyz
Created: 8th May 2026
http://[IP_ADDRESS]:5175
Let's Encrypt
Public
Online
finance-mcp.lakylak.xyz
Created: 9th May 2026
http://[IP_ADDRESS]:3002
Let's Encrypt
Public
Online
gitea.lakylak.xyz
Created: 18th July 2025
http://[IP_ADDRESS]:3052
Let's Encrypt
Public
Online
hydra.lakylak.xyz
Created: 29th March 2026
http://[IP_ADDRESS]:4444
Let's Encrypt
Public
Online
images.lakylak.xyz
Created: 17th June 2025
http://[IP_ADDRESS]:3474
Let's Encrypt
Public
Online
immich.lakylak.xyz
Created: 15th June 2025
http://[IP_ADDRESS]:8212
Let's Encrypt
Public
Online
jellyfin.lakylak.xyz
Created: 15th June 2025
http://[IP_ADDRESS]:8096
Let's Encrypt
Public
Online
lakylak.xyz
Created: 15th June 2025
http://[IP_ADDRESS]:9999
Let's Encrypt
Public
Online
linkwarden.lakylak.xyz
Created: 13th December 2025
http://[IP_ADDRESS]:7461
Let's Encrypt
Public
Online
location-tracker.lakylak.xyz
Created: 30th August 2025
http://[IP_ADDRESS]:8050
Let's Encrypt
Public
Online
log.lakylak.xyz
Created: 23rd September 2025
http://[IP_ADDRESS]:18084
Let's Encrypt
Public
Online
login.lakylak.xyz
Created: 29th March 2026
http://[IP_ADDRESS]:4446
Let's Encrypt
Public
Online
mcp.location.lakylak.xyz
Created: 15th March 2026
http://[IP_ADDRESS]:8052
Let's Encrypt
Public
Online
n8n.lakylak.xyz
Created: 17th July 2025
http://[IP_ADDRESS]:5678
Let's Encrypt
Public
Online
nas.lakylak.xyz
Created: 28th July 2025
http://[IP_ADDRESS]:9999
Let's Encrypt
Public
Online
notes.lakylak.xyz
Created: 31st October 2025
http://[IP_ADDRESS]:8085
Let's Encrypt
Public
Online
obsidian.lakylak.xyz
Created: 17th June 2025
http://[IP_ADDRESS]:3421
Let's Encrypt
Public
Online
outfit.lakylak.xyz
Created: 25th March 2026
http://[IP_ADDRESS]:8667
Let's Encrypt
Public
Online
owntracks.lakylak.xyz
Created: 12th August 2025
http://[IP_ADDRESS]:8083
Let's Encrypt
Public
Online
paperless.lakylak.xyz
Created: 25th October 2025
http://[IP_ADDRESS]:8777
Let's Encrypt
Public
Online
payments.lakylak.xyz
Created: 14th February 2026
http://[IP_ADDRESS]:3010
Let's Encrypt
Public
Online
pdf.lakylak.xyz
Created: 19th June 2025
http://[IP_ADDRESS]:7890
Let's Encrypt
Public
Online
portainer.lakylak.xyz
Created: 15th June 2025
http://[IP_ADDRESS]:9000
Let's Encrypt
Public
Online
...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Pull requests · screenpipe/screenpipe · GitHub","depth":4,"bounds":{"left":0.0,"top":0.0518755,"width":0.016123671,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.0006648936,"top":0.0518755,"width":0.004986702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"DNS / Nameservers | Hostinger","depth":4,"bounds":{"left":0.0,"top":0.08459697,"width":0.016123671,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.0006648936,"top":0.08459697,"width":0.004986702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Nginx Proxy Manager","depth":4,"bounds":{"left":0.0,"top":0.11731844,"width":0.016123671,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.0006648936,"top":0.11731844,"width":0.004986702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Screenpipe — Archive","depth":4,"bounds":{"left":0.0,"top":0.15003991,"width":0.016123671,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.0006648936,"top":0.15003991,"width":0.004986702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"SQLite Web: archive.db","depth":4,"bounds":{"left":0.0,"top":0.18276137,"width":0.016123671,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.0006648936,"top":0.18276137,"width":0.004986702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"SQLite Web: db.sqlite","depth":4,"bounds":{"left":0.0,"top":0.21548285,"width":0.016123671,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.0006648936,"top":0.21548285,"width":0.004986702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub","depth":4,"bounds":{"left":0.0,"top":0.2482043,"width":0.016123671,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.0006648936,"top":0.2482043,"width":0.004986702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"DXP4800PLUS-B5F8","depth":4,"bounds":{"left":0.0,"top":0.28092578,"width":0.016123671,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.0006648936,"top":0.28092578,"width":0.004986702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"AFFiNE - All In One KnowledgeOS","depth":4,"bounds":{"left":0.0,"top":0.31364724,"width":0.016123671,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.0006648936,"top":0.31364724,"width":0.004986702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"All docs · AFFiNE","depth":4,"bounds":{"left":0.0,"top":0.3463687,"width":0.016123671,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.0006648936,"top":0.3463687,"width":0.004986702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Payments Logger","depth":4,"bounds":{"left":0.0,"top":0.3790902,"width":0.016123671,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.0006648936,"top":0.3790902,"width":0.004986702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Your old PC can run Windows 11 in a VM, but not on bare metal - kovaliklukas@gmail.com - Gmail","depth":4,"bounds":{"left":0.0,"top":0.41181165,"width":0.016123671,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.0006648936,"top":0.41181165,"width":0.004986702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Location Logger","depth":4,"bounds":{"left":0.0,"top":0.4445331,"width":0.016123671,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.0006648936,"top":0.4445331,"width":0.004986702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Finance Hub","depth":4,"bounds":{"left":0.0,"top":0.4772546,"width":0.016123671,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.0006648936,"top":0.4772546,"width":0.004986702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Finance Hub","depth":4,"bounds":{"left":0.0,"top":0.509976,"width":0.016123671,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.0006648936,"top":0.509976,"width":0.004986702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Select: transactions - db - Adminer","depth":4,"bounds":{"left":0.0,"top":0.54269755,"width":0.016123671,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.0006648936,"top":0.54269755,"width":0.004986702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Claude Code | Claude Platform","depth":4,"bounds":{"left":0.0,"top":0.575419,"width":0.016123671,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.0006648936,"top":0.575419,"width":0.004986702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Claude","depth":4,"bounds":{"left":0.0,"top":0.60814047,"width":0.016123671,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.0006648936,"top":0.60814047,"width":0.004986702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"lakylak/finance-hub - finance-hub - Gitea: Git with a cup of tea","depth":4,"bounds":{"left":0.0,"top":0.6408619,"width":0.016123671,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.0006648936,"top":0.6408619,"width":0.004986702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Applications - Admin - authentik","depth":4,"bounds":{"left":0.0,"top":0.6735834,"width":0.016123671,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.0006648936,"top":0.6735834,"width":0.004986702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.0028257978,"top":0.70790106,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"bounds":{"left":0.0,"top":0.8547486,"width":0.016123671,"height":0.0311253},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.0,"top":0.8858739,"width":0.016123671,"height":0.027533919},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.0,"top":0.9134078,"width":0.016123671,"height":0.02793296},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bitwarden","depth":6,"bounds":{"left":0.0,"top":0.9413408,"width":0.016123671,"height":0.027533919},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.0,"top":0.9688747,"width":0.016123671,"height":0.0311253},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Nginx Proxy Manager","depth":8,"bounds":{"left":0.09391622,"top":0.061452515,"width":0.06648936,"height":0.03471668},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Nginx Proxy Manager","depth":9,"bounds":{"left":0.10455452,"top":0.06783719,"width":0.055851065,"height":0.018355945},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Admin Administrator","depth":8,"bounds":{"left":0.4424867,"top":0.06584198,"width":0.042386968,"height":0.02593775},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Admin","depth":10,"bounds":{"left":0.45977393,"top":0.06424581,"width":0.013630319,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Administrator","depth":11,"bounds":{"left":0.45977393,"top":0.07980846,"width":0.025099734,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":" Dashboard","depth":10,"bounds":{"left":0.09391622,"top":0.10654429,"width":0.028590426,"height":0.044293694},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":12,"bounds":{"left":0.09391622,"top":0.122505985,"width":0.004654255,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Dashboard","depth":11,"bounds":{"left":0.09990027,"top":0.12051077,"width":0.022606382,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":" Hosts","depth":10,"bounds":{"left":0.13048537,"top":0.10654429,"width":0.01761968,"height":0.044293694},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":12,"bounds":{"left":0.13048537,"top":0.122505985,"width":0.004654255,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Hosts","depth":11,"bounds":{"left":0.13646941,"top":0.12051077,"width":0.011635638,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":" Access Lists","depth":10,"bounds":{"left":0.15608378,"top":0.10654429,"width":0.030086435,"height":0.044293694},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":12,"bounds":{"left":0.15608378,"top":0.122505985,"width":0.004654255,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Access Lists","depth":11,"bounds":{"left":0.16206782,"top":0.12051077,"width":0.024102394,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":" SSL Certificates","depth":10,"bounds":{"left":0.19414894,"top":0.10654429,"width":0.038231384,"height":0.044293694},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":12,"bounds":{"left":0.19414894,"top":0.122505985,"width":0.004654255,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SSL Certificates","depth":11,"bounds":{"left":0.20013298,"top":0.12051077,"width":0.032247342,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":" Users","depth":10,"bounds":{"left":0.24035904,"top":0.10654429,"width":0.017453458,"height":0.044293694},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":12,"bounds":{"left":0.24035904,"top":0.122505985,"width":0.004654255,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Users","depth":11,"bounds":{"left":0.24634309,"top":0.12051077,"width":0.011469414,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":" Audit Log","depth":10,"bounds":{"left":0.26579124,"top":0.10654429,"width":0.025598405,"height":0.044293694},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":12,"bounds":{"left":0.26579124,"top":0.122505985,"width":0.004654255,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Audit Log","depth":11,"bounds":{"left":0.27177528,"top":0.12051077,"width":0.019614361,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":" Settings","depth":10,"bounds":{"left":0.29936835,"top":0.10654429,"width":0.022938829,"height":0.044293694},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":12,"bounds":{"left":0.29936835,"top":0.122505985,"width":0.004654255,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Settings","depth":11,"bounds":{"left":0.3053524,"top":0.12051077,"width":0.016954787,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Proxy Hosts","depth":9,"bounds":{"left":0.1022274,"top":0.1839585,"width":0.029089095,"height":0.017557861},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Proxy Hosts","depth":10,"bounds":{"left":0.1022274,"top":0.18355946,"width":0.029089095,"height":0.018355945},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"","depth":11,"bounds":{"left":0.36319813,"top":0.1867518,"width":0.004986702,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXTextField","text":"Search Host…","depth":10,"bounds":{"left":0.35904256,"top":0.18156424,"width":0.06898271,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"text field","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"","depth":9,"bounds":{"left":0.43068483,"top":0.18156424,"width":0.011469414,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":10,"bounds":{"left":0.43367687,"top":0.1867518,"width":0.005485372,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Add Proxy Host","depth":9,"bounds":{"left":0.44481382,"top":0.18156424,"width":0.034408245,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Add Proxy Host","depth":10,"bounds":{"left":0.44780585,"top":0.1859537,"width":0.028424202,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SOURCE","depth":12,"bounds":{"left":0.12084442,"top":0.22306465,"width":0.016289894,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"DESTINATION","depth":12,"bounds":{"left":0.22207446,"top":0.22306465,"width":0.02642952,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SSL","depth":12,"bounds":{"left":0.32413563,"top":0.22306465,"width":0.0071476065,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ACCESS","depth":12,"bounds":{"left":0.3801529,"top":0.22306465,"width":0.01512633,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"STATUS","depth":12,"bounds":{"left":0.41722074,"top":0.22306465,"width":0.014960106,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ai.chat.lakylak.xyz","depth":12,"bounds":{"left":0.12350399,"top":0.25897846,"width":0.03025266,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 10th March 2026","depth":13,"bounds":{"left":0.12084442,"top":0.28052673,"width":0.045877658,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:11000","depth":13,"bounds":{"left":0.22207446,"top":0.26735833,"width":0.055518616,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"bounds":{"left":0.32413563,"top":0.26735833,"width":0.026928192,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"bounds":{"left":0.3801529,"top":0.26735833,"width":0.013131649,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"bounds":{"left":0.421875,"top":0.26735833,"width":0.014793883,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"bounds":{"left":0.4715758,"top":0.26735833,"width":0.004986702,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"bounds":{"left":0.4715758,"top":0.26855546,"width":0.004986702,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app.lakylak.xyz","depth":12,"bounds":{"left":0.12350399,"top":0.31843576,"width":0.02543218,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 19th July 2025","depth":13,"bounds":{"left":0.12084442,"top":0.33998403,"width":0.042386968,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:18083","depth":13,"bounds":{"left":0.22207446,"top":0.3272147,"width":0.055518616,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"bounds":{"left":0.32413563,"top":0.3272147,"width":0.026928192,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"bounds":{"left":0.3801529,"top":0.3272147,"width":0.013131649,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"bounds":{"left":0.421875,"top":0.3272147,"width":0.014793883,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"bounds":{"left":0.4715758,"top":0.3272147,"width":0.004986702,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"bounds":{"left":0.4715758,"top":0.32841182,"width":0.004986702,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app.payments.lakylak.xyz","depth":12,"bounds":{"left":0.12350399,"top":0.37789306,"width":0.04288564,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 14th February 2026","depth":13,"bounds":{"left":0.12084442,"top":0.39944133,"width":0.05119681,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:5174","depth":13,"bounds":{"left":0.22207446,"top":0.386672,"width":0.053025264,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"bounds":{"left":0.32413563,"top":0.386672,"width":0.026928192,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"bounds":{"left":0.3801529,"top":0.386672,"width":0.013131649,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"bounds":{"left":0.421875,"top":0.386672,"width":0.014793883,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"bounds":{"left":0.4715758,"top":0.386672,"width":0.004986702,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"bounds":{"left":0.4715758,"top":0.38786912,"width":0.004986702,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app.screenpipe.lakylak.xyz","depth":12,"bounds":{"left":0.12350399,"top":0.43774942,"width":0.04488032,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 27th April 2026","depth":13,"bounds":{"left":0.12084442,"top":0.4592977,"width":0.043218084,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:8766","depth":13,"bounds":{"left":0.22207446,"top":0.4461293,"width":0.053025264,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"bounds":{"left":0.32413563,"top":0.4461293,"width":0.026928192,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"bounds":{"left":0.3801529,"top":0.4461293,"width":0.013131649,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"bounds":{"left":0.421875,"top":0.4461293,"width":0.014793883,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"bounds":{"left":0.4715758,"top":0.4461293,"width":0.004986702,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"bounds":{"left":0.4715758,"top":0.44732642,"width":0.004986702,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"audiobook.lakylak.xyz","depth":12,"bounds":{"left":0.12350399,"top":0.49720672,"width":0.03723404,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 15th June 2025","depth":13,"bounds":{"left":0.12084442,"top":0.51875496,"width":0.043716755,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168..242:13378","depth":13,"bounds":{"left":0.22207446,"top":0.5059856,"width":0.053025264,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"bounds":{"left":0.32413563,"top":0.5059856,"width":0.026928192,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"bounds":{"left":0.3801529,"top":0.5059856,"width":0.013131649,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"bounds":{"left":0.421875,"top":0.5059856,"width":0.014793883,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"bounds":{"left":0.4715758,"top":0.5059856,"width":0.004986702,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"bounds":{"left":0.4715758,"top":0.5071828,"width":0.004986702,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"auth.lakylak.xyz","depth":12,"bounds":{"left":0.12350399,"top":0.556664,"width":0.026761968,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 30th March 2026","depth":13,"bounds":{"left":0.12084442,"top":0.5786113,"width":0.045877658,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:9100","depth":13,"bounds":{"left":0.22207446,"top":0.5654429,"width":0.053025264,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"bounds":{"left":0.32413563,"top":0.5654429,"width":0.026928192,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"bounds":{"left":0.3801529,"top":0.5654429,"width":0.013131649,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"bounds":{"left":0.421875,"top":0.5654429,"width":0.014793883,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"bounds":{"left":0.4715758,"top":0.5654429,"width":0.004986702,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"bounds":{"left":0.4715758,"top":0.5666401,"width":0.004986702,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"backup.lakylak.xyz","depth":12,"bounds":{"left":0.12350399,"top":0.61652035,"width":0.03125,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 10th July 2025","depth":13,"bounds":{"left":0.12084442,"top":0.6380686,"width":0.042386968,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.243:9999","depth":13,"bounds":{"left":0.22207446,"top":0.6249002,"width":0.053025264,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"bounds":{"left":0.32413563,"top":0.6249002,"width":0.026928192,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"bounds":{"left":0.3801529,"top":0.6249002,"width":0.013131649,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"bounds":{"left":0.421875,"top":0.6249002,"width":0.014793883,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"bounds":{"left":0.4715758,"top":0.6249002,"width":0.004986702,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"bounds":{"left":0.4715758,"top":0.6260974,"width":0.004986702,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"beszel.lakylak.xyz","depth":12,"bounds":{"left":0.12350399,"top":0.67597765,"width":0.029587766,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 6th December 2025","depth":13,"bounds":{"left":0.12084442,"top":0.6975259,"width":0.05119681,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:8095","depth":13,"bounds":{"left":0.22207446,"top":0.6847566,"width":0.053025264,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"bounds":{"left":0.32413563,"top":0.6847566,"width":0.026928192,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"bounds":{"left":0.3801529,"top":0.6847566,"width":0.013131649,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"bounds":{"left":0.421875,"top":0.6847566,"width":0.014793883,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"bounds":{"left":0.4715758,"top":0.6847566,"width":0.004986702,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"bounds":{"left":0.4715758,"top":0.68595374,"width":0.004986702,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"bitwarden.lakylak.xyz","depth":12,"bounds":{"left":0.12350399,"top":0.73543495,"width":0.036236703,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 16th June 2025","depth":13,"bounds":{"left":0.12084442,"top":0.7573823,"width":0.043716755,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:9890","depth":13,"bounds":{"left":0.22207446,"top":0.7442139,"width":0.053025264,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"bounds":{"left":0.32413563,"top":0.7442139,"width":0.026928192,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"bounds":{"left":0.3801529,"top":0.7442139,"width":0.013131649,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"bounds":{"left":0.421875,"top":0.7442139,"width":0.014793883,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"bounds":{"left":0.4715758,"top":0.7442139,"width":0.004986702,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"bounds":{"left":0.4715758,"top":0.74541104,"width":0.004986702,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"book.lakylak.xyz","depth":12,"bounds":{"left":0.12350399,"top":0.7952913,"width":0.027593086,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 31st October 2025","depth":13,"bounds":{"left":0.12084442,"top":0.8168396,"width":0.04886968,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:6060","depth":13,"bounds":{"left":0.22207446,"top":0.8036712,"width":0.053025264,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"bounds":{"left":0.32413563,"top":0.8036712,"width":0.026928192,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"bounds":{"left":0.3801529,"top":0.8036712,"width":0.013131649,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"bounds":{"left":0.421875,"top":0.8036712,"width":0.014793883,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"bounds":{"left":0.4715758,"top":0.8036712,"width":0.004986702,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"bounds":{"left":0.4715758,"top":0.80486834,"width":0.004986702,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"crm.lakylak.xyz","depth":12,"bounds":{"left":0.12350399,"top":0.8547486,"width":0.025598405,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 25th July 2025","depth":13,"bounds":{"left":0.12084442,"top":0.8762969,"width":0.042386968,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:3353","depth":13,"bounds":{"left":0.22207446,"top":0.86352754,"width":0.053025264,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"bounds":{"left":0.32413563,"top":0.86352754,"width":0.026928192,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"bounds":{"left":0.3801529,"top":0.86352754,"width":0.013131649,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"bounds":{"left":0.421875,"top":0.86352754,"width":0.014793883,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"bounds":{"left":0.4715758,"top":0.86352754,"width":0.004986702,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"bounds":{"left":0.4715758,"top":0.86472464,"width":0.004986702,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"dawarich.lakylak.xyz","depth":12,"bounds":{"left":0.12350399,"top":0.91460496,"width":0.034408245,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 25th August 2025","depth":13,"bounds":{"left":0.12084442,"top":0.93615323,"width":0.04720745,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:3000","depth":13,"bounds":{"left":0.22207446,"top":0.92298484,"width":0.053025264,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"bounds":{"left":0.32413563,"top":0.92298484,"width":0.026928192,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"bounds":{"left":0.3801529,"top":0.92298484,"width":0.013131649,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"bounds":{"left":0.421875,"top":0.92298484,"width":0.014793883,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"bounds":{"left":0.4715758,"top":0.92298484,"width":0.004986702,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"bounds":{"left":0.4715758,"top":0.92418194,"width":0.004986702,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"db.screenpipe.lakylak.xyz","depth":12,"bounds":{"left":0.12350399,"top":0.97406226,"width":0.04288564,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 27th April 2026","depth":13,"bounds":{"left":0.12084442,"top":0.99561054,"width":0.043218084,"height":0.004389465},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:8767","depth":13,"bounds":{"left":0.22207446,"top":0.9828412,"width":0.053025264,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"bounds":{"left":0.32413563,"top":0.9828412,"width":0.026928192,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"bounds":{"left":0.3801529,"top":0.9828412,"width":0.013131649,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"bounds":{"left":0.421875,"top":0.9828412,"width":0.014793883,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"bounds":{"left":0.4715758,"top":0.9828412,"width":0.004986702,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"bounds":{"left":0.4715758,"top":0.9840383,"width":0.004986702,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"dsk-uploader.lakylak.xyz","depth":12,"bounds":{"left":0.12350399,"top":1.0,"width":0.04089096,"height":-0.033519506},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 15th August 2025","depth":13,"bounds":{"left":0.12084442,"top":1.0,"width":0.04720745,"height":-0.055067778},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:8502","depth":13,"bounds":{"left":0.22207446,"top":1.0,"width":0.053025264,"height":-0.042298436},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"bounds":{"left":0.32413563,"top":1.0,"width":0.026928192,"height":-0.042298436},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"bounds":{"left":0.3801529,"top":1.0,"width":0.013131649,"height":-0.042298436},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"bounds":{"left":0.421875,"top":1.0,"width":0.014793883,"height":-0.042298436},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"bounds":{"left":0.4715758,"top":1.0,"width":0.004986702,"height":-0.042298436},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"bounds":{"left":0.4715758,"top":1.0,"width":0.004986702,"height":-0.043495655},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"finance-hub.lakylak.xyz","depth":12,"bounds":{"left":0.12350399,"top":1.0,"width":0.0390625,"height":-0.09337592},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 8th May 2026","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:5175","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"finance-mcp.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 9th May 2026","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:3002","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"gitea.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 18th July 2025","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:3052","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"hydra.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 29th March 2026","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:4444","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"images.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 17th June 2025","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:3474","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"immich.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 15th June 2025","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:8212","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"jellyfin.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 15th June 2025","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:8096","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 15th June 2025","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:9999","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"linkwarden.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 13th December 2025","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:7461","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"location-tracker.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 30th August 2025","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:8050","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"log.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 23rd September 2025","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:18084","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"login.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 29th March 2026","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:4446","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"mcp.location.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 15th March 2026","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:8052","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"n8n.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 17th July 2025","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:5678","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"nas.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 28th July 2025","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:9999","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"notes.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 31st October 2025","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:8085","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"obsidian.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 17th June 2025","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:3421","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"outfit.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 25th March 2026","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:8667","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"owntracks.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 12th August 2025","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:8083","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"paperless.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 25th October 2025","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:8777","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"payments.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 14th February 2026","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:3010","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"pdf.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 19th June 2025","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:7890","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"portainer.lakylak.xyz","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created: 15th June 2025","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"http://192.168.0.242:9000","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let's Encrypt","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Online","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-4948973334286784779
|
-4931691133008957385
|
visual_change
|
accessibility
|
NULL
|
Pull requests · screenpipe/screenpipe · GitHub
Clo Pull requests · screenpipe/screenpipe · GitHub
Close tab
DNS / Nameservers | Hostinger
Close tab
Nginx Proxy Manager
Close tab
Screenpipe — Archive
Close tab
SQLite Web: archive.db
Close tab
SQLite Web: db.sqlite
Close tab
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
Close tab
DXP4800PLUS-B5F8
Close tab
AFFiNE - All In One KnowledgeOS
Close tab
All docs · AFFiNE
Close tab
Payments Logger
Close tab
Your old PC can run Windows 11 in a VM, but not on bare metal - [EMAIL] - Gmail
Close tab
Location Logger
Close tab
Finance Hub
Close tab
Finance Hub
Close tab
Select: transactions - db - Adminer
Close tab
Claude Code | Claude Platform
Close tab
Claude
Close tab
lakylak/finance-hub - finance-hub - Gitea: Git with a cup of tea
Close tab
Applications - Admin - authentik
Close tab
New Tab
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Customize sidebar
Nginx Proxy Manager
Nginx Proxy Manager
Admin Administrator
Admin
Administrator
Dashboard
Dashboard
Hosts
Hosts
Access Lists
Access Lists
SSL Certificates
SSL Certificates
Users
Users
Audit Log
Audit Log
Settings
Settings
Proxy Hosts
Proxy Hosts
Search Host…
Add Proxy Host
Add Proxy Host
SOURCE
DESTINATION
SSL
ACCESS
STATUS
ai.chat.lakylak.xyz
Created: 10th March 2026
http://[IP_ADDRESS]:11000
Let's Encrypt
Public
Online
app.lakylak.xyz
Created: 19th July 2025
http://[IP_ADDRESS]:18083
Let's Encrypt
Public
Online
app.payments.lakylak.xyz
Created: 14th February 2026
http://[IP_ADDRESS]:5174
Let's Encrypt
Public
Online
app.screenpipe.lakylak.xyz
Created: 27th April 2026
http://[IP_ADDRESS]:8766
Let's Encrypt
Public
Online
audiobook.lakylak.xyz
Created: 15th June 2025
http://192.168..242:13378
Let's Encrypt
Public
Online
auth.lakylak.xyz
Created: 30th March 2026
http://[IP_ADDRESS]:9100
Let's Encrypt
Public
Online
backup.lakylak.xyz
Created: 10th July 2025
http://[IP_ADDRESS]:9999
Let's Encrypt
Public
Online
beszel.lakylak.xyz
Created: 6th December 2025
http://[IP_ADDRESS]:8095
Let's Encrypt
Public
Online
bitwarden.lakylak.xyz
Created: 16th June 2025
http://[IP_ADDRESS]:9890
Let's Encrypt
Public
Online
book.lakylak.xyz
Created: 31st October 2025
http://[IP_ADDRESS]:6060
Let's Encrypt
Public
Online
crm.lakylak.xyz
Created: 25th July 2025
http://[IP_ADDRESS]:3353
Let's Encrypt
Public
Online
dawarich.lakylak.xyz
Created: 25th August 2025
http://[IP_ADDRESS]:3000
Let's Encrypt
Public
Online
db.screenpipe.lakylak.xyz
Created: 27th April 2026
http://[IP_ADDRESS]:8767
Let's Encrypt
Public
Online
dsk-uploader.lakylak.xyz
Created: 15th August 2025
http://[IP_ADDRESS]:8502
Let's Encrypt
Public
Online
finance-hub.lakylak.xyz
Created: 8th May 2026
http://[IP_ADDRESS]:5175
Let's Encrypt
Public
Online
finance-mcp.lakylak.xyz
Created: 9th May 2026
http://[IP_ADDRESS]:3002
Let's Encrypt
Public
Online
gitea.lakylak.xyz
Created: 18th July 2025
http://[IP_ADDRESS]:3052
Let's Encrypt
Public
Online
hydra.lakylak.xyz
Created: 29th March 2026
http://[IP_ADDRESS]:4444
Let's Encrypt
Public
Online
images.lakylak.xyz
Created: 17th June 2025
http://[IP_ADDRESS]:3474
Let's Encrypt
Public
Online
immich.lakylak.xyz
Created: 15th June 2025
http://[IP_ADDRESS]:8212
Let's Encrypt
Public
Online
jellyfin.lakylak.xyz
Created: 15th June 2025
http://[IP_ADDRESS]:8096
Let's Encrypt
Public
Online
lakylak.xyz
Created: 15th June 2025
http://[IP_ADDRESS]:9999
Let's Encrypt
Public
Online
linkwarden.lakylak.xyz
Created: 13th December 2025
http://[IP_ADDRESS]:7461
Let's Encrypt
Public
Online
location-tracker.lakylak.xyz
Created: 30th August 2025
http://[IP_ADDRESS]:8050
Let's Encrypt
Public
Online
log.lakylak.xyz
Created: 23rd September 2025
http://[IP_ADDRESS]:18084
Let's Encrypt
Public
Online
login.lakylak.xyz
Created: 29th March 2026
http://[IP_ADDRESS]:4446
Let's Encrypt
Public
Online
mcp.location.lakylak.xyz
Created: 15th March 2026
http://[IP_ADDRESS]:8052
Let's Encrypt
Public
Online
n8n.lakylak.xyz
Created: 17th July 2025
http://[IP_ADDRESS]:5678
Let's Encrypt
Public
Online
nas.lakylak.xyz
Created: 28th July 2025
http://[IP_ADDRESS]:9999
Let's Encrypt
Public
Online
notes.lakylak.xyz
Created: 31st October 2025
http://[IP_ADDRESS]:8085
Let's Encrypt
Public
Online
obsidian.lakylak.xyz
Created: 17th June 2025
http://[IP_ADDRESS]:3421
Let's Encrypt
Public
Online
outfit.lakylak.xyz
Created: 25th March 2026
http://[IP_ADDRESS]:8667
Let's Encrypt
Public
Online
owntracks.lakylak.xyz
Created: 12th August 2025
http://[IP_ADDRESS]:8083
Let's Encrypt
Public
Online
paperless.lakylak.xyz
Created: 25th October 2025
http://[IP_ADDRESS]:8777
Let's Encrypt
Public
Online
payments.lakylak.xyz
Created: 14th February 2026
http://[IP_ADDRESS]:3010
Let's Encrypt
Public
Online
pdf.lakylak.xyz
Created: 19th June 2025
http://[IP_ADDRESS]:7890
Let's Encrypt
Public
Online
portainer.lakylak.xyz
Created: 15th June 2025
http://[IP_ADDRESS]:9000
Let's Encrypt
Public
Online
...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
14192
|
629
|
43
|
2026-05-09T17:04:04.106184+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-09/1778 /Users/lukas/.screenpipe/data/data/2026-05-09/1778346244106_m1.jpg...
|
Code
|
Implement Authentik inte… — finance [SSH: nas]
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Explorer (⇧⌘E)
Search (⇧⌘F)
Source Control (⌃⇧ Explorer (⇧⌘E)
Search (⇧⌘F)
Source Control (⌃⇧G) - 12 pending changes
12
Run and Debug (⇧⌘D)
Remote Explorer
Extensions (⇧⌘X) - 2 require update
2
Claude Code
Containers
EXPLORER
EXPLORER
Explorer Section: finance [SSH: nas]
Explorer Section: finance [SSH: nas]
FINANCE [SSH: NAS]
auth
dsk-uploader
finance-hub
backend
frontend
mcp
scripts
.env
.env.example
M
.gitignore
M
docker-compose.yml
M
README.md
sms_export.json
payments-logger
Outline Section
OUTLINE
OUTLINE
Timeline Section
TIMELINE
TIMELINE
docker-compose.yml, Editor Group 1
.env, Editor Group 1
.env.example, preview, Editor Group 1
report(1).csv, Editor Group 1
report(2).csv, Editor Group 1
sms_export.json, Editor Group 1
# ── Database ───────────────────────────────────────────────────────────────────
[ENV_SECRET]
# ── Notifier service ──────────────────────────────────────────────────────────
NOTIFIER_URL=[URL_WITH_CREDENTIALS]
# Secret key — generate with: openssl rand -base64 36
[ENV_SECRET]
# Public URL authentik is reachable at (used for redirects and the outpost)
AUTHENTIK_HOST=[URL_WITH_CREDENTIALS] version 2>/dev/null && node --version
Copy code to clipboard
OUT
Exit code 127
Bash
Verify public path configuration
IN
# Check if the upload endpoints are really public
grep -n 'PUBLIC_PATHS\|upload\|ingest' /volume2/docker/finance/finance-hub/backend/src/auth.js
Copy code to clipboard
OUT
<tool_use_error>Cancelled: parallel tool call Bash(npm view @modelcontextprotocol/sdk versi…) errored</tool_use_error>
Bash
Check node version and MCP SDK latest
IN
node --version 2>/dev/null && python3 -c "import urllib.request; import json; d=json.loads(urllib.request.urlopen('[URL_WITH_CREDENTIALS] "^1.29.0"
},
"engines": {
"node": ">=18"
}
}
Write
server.js
server.js
236 lines
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import {
CallToolRequestSchema,
ListToolsRequestSchema,
} from '@modelcontextprotocol/sdk/types.js';
const BASE_URL = (process.env.FINANCE_HUB_URL || '[URL_WITH_CREDENTIALS] '^1.29.0'}
Thinking
Thinking
Good. Now let me test the MCP server can at least start and call the health check:
Bash
Smoke test MCP server startup
IN
FINANCE_HUB_URL=http://localhost:3001 [ENV_SECRET] \
echo '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' | timeout 5 node server.js 2>/dev/null | head -3 || echo "NODE test (expected timeout on stdin wait)"
Copy code to clipboard
OUT
{"result":{"tools":[{"name":"list_transactions","description":"List finance transactions with optional filters. Returns paginated results including total amount for the filtered set.","inputSchema":{"type":"object","properties":{"page":{"type":"number","description":"Page number (default 1)"},"limit":{"type":"number","description":"Results per page, max 200 (default 50)"},"dateFrom":{"type":"string","description":"Start date YYYY-MM-DD (inclusive)"},"dateTo":{"type":"string","description":"End date YYYY-MM-DD (inclusive)"},"tag":{"type":"string","description":"Filter by tag name"},"recipient":{"type":"string","description":"Substring match on payee name"},"type":{"type":"string","description":"Transaction type: POS | ATM | WALLET"},"source":{"type":"string","description":"Import source: INGEST | UPLOAD"},"search":{"type":"string","description":"Full-text search across rawMessage and recipient"},"hideBalanceAlerts":{"type":"boolean","description":"Exclude balance-notification SMS (default false)"},"sortBy":{"type":"string","description":"Sort field: date | amount | recipient | createdAt"},"sortDir":{"type":"string","description":"asc or desc (default desc)"}}}},{"name":"spending_by_tag","description":"Aggregate spending totals by tag for a date range. Fetches up to 200 transactions and groups them. Good for monthly summaries.","inputSchema":{"type":"object","properties":{"dateFrom":{"type":"string","description":"Start date YYYY-MM-DD"},"dateTo":{"type":"string","description":"End date YYYY-MM-DD"}}}},{"name":"get_transaction","description":"Get a single transaction by its numeric ID.","inputSchema":{"type":"object","required":["id"],"properties":{"id":{"type":"number","description":"Transaction import ID"}}}},{"name":"list_tags","description":"List all available tags with their colors.","inputSchema":{"type":"object","properties":{}}},{"name":"add_tag","description":"Add a tag to a transaction. Creates the tag globally if it does not exist.","inputSchema":{"type":"object","required":["id","name"],"properties":{"id":{"type":"number","description":"Transaction ID"},"name":{"type":"string","description":"Tag name (e.g. \"Groceries\")"},"color":{"type":"string","description":"Hex color (e.g. \"#22c55e\"). Optional — auto-assigned if omitted."}}}},{"name":"remove_tag","description":"Remove a tag from a transaction.","inputSchema":{"type":"object","required":["id","tagId"],"properties":{"id":{"type":"number","description":"Transaction ID"},"tagId":{"type":"number","description":"Tag ID (from list_tags or the transaction object)"}}}},{"name":"health_check","description":"Check Finance Hub backend connectivity and database status.","inputSchema":{"type":"object","properties":{}}}]},"jsonrpc":"2.0","id":1}
Thinking
Thinking
MCP server responds correctly. Now test an actual tool call:
Bash
Test MCP health_check tool against live backend
IN
\
printf '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}\n{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"health_check","arguments":{}}}\n' | \
FINANCE_HUB_URL=http://localhost:3001 [ENV_SECRET] \
timeout 5 node server.js 2>/dev/null | tail -1 | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['result']['content'][0]['text'])"
Copy code to clipboard
OUT
{
"status": "ok",
"timestamp": "2026-05-09T16:19:09.977Z",
"storage": {
"type": "PostgreSQL",
"host": "db",
"database": "finance_hub"
}
}
Bash
Rebuild backend with API key auth changes
IN
# Test the API key auth directly against the backend (backend still has DEV_BYPASS_AUTH=true, need to restart first)
# First rebuild with the new code
cd /volume2/docker/finance/finance-hub && docker compose up -d --build backend 2>&1 | tail -8
Copy code to clipboard
OUT
time="2026-05-09T19:19:13+03:00" level=warning msg="/volume2/docker/finance/finance-hub/docker-compose.yml: `version` is obsolete"
permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get "http://%2Fvar%2Frun%2Fdocker.sock/v1.45/containers/json?all=1&filters=%7B%22label%22%3A%7B%22com.docker.compose.config-hash%22%3Atrue%2C%22com.docker.compose.project%3Dfinance-hub%22%3Atrue%7D%7D": dial unix /var/run/docker.sock: connect: permission denied
Bash
Rebuild backend with sudo
IN
sudo docker compose -f /volume2/docker/finance/finance-hub/docker-compose.yml up -d --build backend 2>&1 | tail -10
Copy code to clipboard
OUT
sudo: a terminal is required to read the password; either use the -S option to read from standard input or configure an askpass helper
sudo: a password is required
Thinking
Thinking
Docker needs sudo+password. Let me verify the auth changes are correct by testing the logic directly:
Bash
Unit test the auth middleware logic
IN
node - << 'EOF'
// Simulate the auth middleware logic
const [ENV_SECRET];
process.env.API_KEY = API_KEY;
const { authentikMiddleware } = require('/volume2/docker/finance/finance-hub/backend/src/auth.js');
function testReq(path, headers = {}) {
const res = { status(code) { this.code = code; return this; }, json(body) { return body; } };
const req = { path, headers };
let passed = false;
authentikMiddleware(req, res, () => { passed = true; });
return { passed, code: res.code, user: req.user };
}
// Public path — no auth needed
let r = testReq('/api/health', {});
console.assert(r.passed, 'health should be public');
console.log('✓ /api/health is public');
// Valid API key
r = testReq('/api/payments', { authorization: `Bearer ${API_KEY}` });
console.assert(r.passed, 'valid key should pass');
console.assert(r.user.username === 'api-key', 'api user');
console.log('✓ valid API key passes');
// Wrong API key
r = testReq('/api/payments', { authorization: 'Bearer wrongkey' });
console.assert(!r.passed, 'wrong key should fail');
console.assert(r.code === 401, '401 on bad key');
console.log('✓ wrong API key returns 401');
// No auth + no bypass + no authentik header
process.env.DEV_BYPASS_AUTH = 'false';
r = testReq('/api/payments', {});
console.assert(!r.passed && r.code === 401, 'no creds → 401');
console.log('✓ no credentials returns 401');
// Upload endpoints no longer public
r = testReq('/api/upload/csv', {});
console.assert(!r.passed && r.code === 401, 'upload/csv requires auth');
console.log('✓ /api/upload/csv now requires auth (was public, now fixed)');
// Authentik header pass-through
r = testReq('/api/payments', { 'x-authentik-username': 'lukastest', 'x-authentik-email': '[EMAIL]' });
console.assert(r.passed && r.user.username === 'lukastest', 'authentik header works');
console.log('✓ Authentik X-authentik-username header works');
console.log('\nAll auth tests passed.');
EOF
Copy code to clipboard
OUT
✓ /api/health is public
✓ valid API key passes
✓ wrong API key returns 401
✓ no credentials returns 401
✓ /api/upload/csv now requires auth (was public, now fixed)
✓ Authentik X-authentik-username header works
All auth tests passed.
All auth cases pass. Now test the MCP spending_by_tag tool against the live backend (with DEV_BYPASS_AUTH still on):
Bash
Test spending_by_tag MCP tool against live backend
IN
cd /volume2/docker/finance/finance-hub/mcp && \
printf '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}\n{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"spending_by_tag","arguments":{"dateFrom":"2026-05-01","dateTo":"2026-05-09"}}}\n' | \
FINANCE_HUB_URL=http://localhost:3001 [ENV_SECRET] \
timeout 8 node server.js 2>/dev/null | grep '"id":2' | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['result']['content'][0]['text'][:500])"
Copy code to clipboard
OUT
{
"period": {
"from": "2026-05-01",
"to": "2026-05-09"
},
"totalTransactions": 36,
"breakdown": [
{
"tag": "Bills",
"total": 117.9,
"count": 6
},
{
"tag": "(untagged)",
"total": 1153.87,
"count": 22
}
]
}
MCP tools work correctly against real data. Let me write the Claude desktop config example and the
.gitignore
for the mcp dir:
Write
claude_desktop_config.example.json
claude_desktop_config.example.json
14 lines
{
"_comment": "Add this block to ~/.config/claude/claude_desktop_config.json (macOS: ~/Library/Application Support/Claude/claude_desktop_config.json)",
"mcpServers": {
"finance-hub": {
"command": "node",
"args": ["/volume2/docker/finance/finance-hub/mcp/server.js"],
"env": {
"FINANCE_HUB_URL": "http://localhost:3001",
"FINANCE_HUB_API_KEY": "94bb2917b9a1b9dcbaec49e7009c2a6b222fc310d32f530aa07e411e8d4a058c"
}
}
}
}
Write
.gitignore
.gitignore
2 lines
node_modules/
Update Todos
Fix auth.js: add API key support + remove upload endpoints from PUBLIC_PATHS
Update index.js: add CORS origin restriction via env var
Update .env and .env.example with API_KEY variable
Build MCP server (stdio, Claude desktop compatible)
Test: restart backend, verify API key auth and MCP connection
Now let me save relevant project context to memory:
Read
MEMORY.md
MEMORY.md
Write
MEMORY.md
MEMORY.md
4 lines
# Memory Index
- [project_finance_hub.md](project_finance_hub.md) — Finance Hub architecture, auth design, MCP server, API key setup
Write
project_finance_hub.md
project_finance_hub.md
35 lines
---
name: Finance Hub project state
description: Architecture, auth design, API key, MCP server location and tools for the finance-hub project
type: project
---
Finance Hub is a personal finance tracker at `/volume2/docker/finance/finance-hub/`.
**Running services** (as of 2026-05-09):
- Backend: port 3001 (Express/Prisma, PostgreSQL)
- Frontend: port 5175 (React/Vite)
- Adminer: port 8092
- Authentik: port 9100 (auth.lakylak.xyz, tag 2026.2.1)
**Auth design:**
- Production: NPM (Nginx Proxy Manager) + Authentik forward-auth outpost → injects `X-authentik-username` header
- `DEV_BYPASS_AUTH=true` is currently set in `.env` — app runs without real auth
- API key auth added: `Authorization: Bearer <API_KEY>` bypasses Authentik header check (used by MCP/scripts)
- API_KEY in `.env`: `94bb2917b9a1b9dcbaec49e7009c2a6b222fc310d32f530aa07e411e8d4a058c`
**Public endpoints** (no auth): `/api/health`, `/api/payments/ingest`
**Security fix applied (2026-05-09):** Removed `/api/upload/csv` and `/api/upload/preview` from PUBLIC_PATHS — they were incorrectly public.
**MCP server:** `/volume2/docker/finance/finance-hub/mcp/server.js`
- Stdio transport, works with Claude desktop
- Tools: list_transactions, spending_by_tag, get_transaction, list_tags, add_tag, remove_tag, health_check
- Env: FINANCE_HUB_URL, FINANCE_HUB_API_KEY
- Config example: `mcp/claude_desktop_config.example.json`
**To enable real Authentik auth:** Set `DEV_BYPASS_AUTH=false` in `.env`, configure NPM proxy host for finance-hub w...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Explorer (⇧⌘E)","depth":19,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":true},{"role":"AXStaticText","text":"","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Search (⇧⌘F)","depth":19,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Source Control (⌃⇧G) - 12 pending changes","depth":19,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"12","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Run and Debug (⇧⌘D)","depth":19,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Remote Explorer","depth":19,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Extensions (⇧⌘X) - 2 require update","depth":19,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"2","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Claude Code","depth":19,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"Containers","depth":19,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"EXPLORER","depth":17,"on_screen":true,"role_description":"heading"},{"role":"AXStaticText","text":"EXPLORER","depth":18,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Explorer Section: finance [SSH: nas]","depth":21,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXHeading","text":"Explorer Section: finance [SSH: nas]","depth":22,"on_screen":true,"role_description":"heading"},{"role":"AXStaticText","text":"FINANCE [SSH: NAS]","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"auth","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"dsk-uploader","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"finance-hub","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"backend","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"frontend","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"mcp","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"scripts","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":".env","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":".env.example","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"M","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":".gitignore","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"M","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"docker-compose.yml","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"M","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"README.md","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"sms_export.json","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"payments-logger","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Outline Section","depth":21,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXHeading","text":"OUTLINE","depth":22,"on_screen":true,"role_description":"heading"},{"role":"AXStaticText","text":"OUTLINE","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Timeline Section","depth":21,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXHeading","text":"TIMELINE","depth":22,"on_screen":true,"role_description":"heading"},{"role":"AXStaticText","text":"TIMELINE","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"docker-compose.yml, Editor Group 1","depth":28,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":".env, Editor Group 1","depth":28,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXRadioButton","text":".env.example, preview, Editor Group 1","depth":28,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"report(1).csv, Editor Group 1","depth":28,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"report(2).csv, Editor Group 1","depth":28,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"sms_export.json, Editor Group 1","depth":28,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":29,"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"# ── Database ───────────────────────────────────────────────────────────────────\nDB_PASSWORD=payments_secret\n\n# ── Notifier service ──────────────────────────────────────────────────────────\nNOTIFIER_URL=https://notifier.lakylak.xyz\nNOTIFIER_CHANNEL=viber\nNOTIFY_DEFAULT_PHONE=+359000000000\n\n# ── Timezone ─────────────────────────────────────────────────────────────────\nTZ=Europe/Sofia\n\n# ── API key auth — for MCP server, scripts, iOS shortcuts on protected endpoints ──\n# Generate with: openssl rand -hex 32\nAPI_KEY=94bb2917b9a1b9dcbaec49e7009c2a6b222fc310d32f530aa07e411e8d4a058c\n\n# ── Dev only — set false and configure NPM+Authentik for production ──────────\n# DEV_BYPASS_AUTH=true","depth":28,"on_screen":true,"value":"# ── Database ───────────────────────────────────────────────────────────────────\nDB_PASSWORD=payments_secret\n\n# ── Notifier service ──────────────────────────────────────────────────────────\nNOTIFIER_URL=https://notifier.lakylak.xyz\nNOTIFIER_CHANNEL=viber\nNOTIFY_DEFAULT_PHONE=+359000000000\n\n# ── Timezone ─────────────────────────────────────────────────────────────────\nTZ=Europe/Sofia\n\n# ── API key auth — for MCP server, scripts, iOS shortcuts on protected endpoints ──\n# Generate with: openssl rand -hex 32\nAPI_KEY=94bb2917b9a1b9dcbaec49e7009c2a6b222fc310d32f530aa07e411e8d4a058c\n\n# ── Dev only — set false and configure NPM+Authentik for production ──────────\n# DEV_BYPASS_AUTH=true","role_description":"editor","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"# ── Database ───────────────────────────────────────────────────────────────────\nDB_PASSWORD=payments_secret\n\n# ── Notifier service ──────────────────────────────────────────────────────────\nNOTIFIER_URL=https://notifier.lakylak.xyz\nNOTIFIER_CHANNEL=viber\nNOTIFY_DEFAULT_PHONE=+359000000000\n\n# ── Timezone ─────────────────────────────────────────────────────────────────\nTZ=Europe/Sofia\n\n# ── API key auth — for MCP server, scripts, iOS shortcuts on protected endpoints ──\n# Generate with: openssl rand -hex 32\nAPI_KEY=94bb2917b9a1b9dcbaec49e7009c2a6b222fc310d32f530aa07e411e8d4a058c\n\n# ── Dev only — set false and configure NPM+Authentik for production ──────────\n# DEV_BYPASS_AUTH=true","depth":29,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Design new payment-logge…, Editor Group 2","depth":28,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"Implement Authentik inte…, Editor Group 2","depth":28,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXButton","text":"remote SSH: nas","depth":16,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":17,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"SSH: nas","depth":17,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"finance-hub (Git) - main*, Checkout Branch/Tag...","depth":16,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":17,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"main*","depth":17,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"finance-hub (Git) - Synchronize Changes","depth":16,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"No Problems","depth":16,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":17,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"0","depth":17,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":17,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"0","depth":17,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"No Ports Forwarded","depth":16,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":17,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"0","depth":17,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Notifications","depth":16,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sign In","depth":16,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":17,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Sign In","depth":17,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Info: Setting up SSH Host nas: Setting up SSH tunnel","depth":12,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Implement Authentik integration with security review","depth":19,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Session history","depth":19,"on_screen":true,"help_text":"Session history","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New session","depth":19,"on_screen":true,"help_text":"New session","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Message actions","depth":24,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"README.md","depth":23,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"README.md","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"lets work on authentication. I want to be able to connect using authentik. REveiw copy of the project in auth folder. Lets test it and establish security. There should be simple way to reauthorize automatically for api and also there should be claude chat compatible mcp with autorization that si stable. Think about it test it and then provide suggestions","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":23,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Thinking","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Let me explore the project structure first, particularly the auth folder.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"List finance directory structure","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"find /volume2/docker/finance -type f | head -80 && echo \"---\" && ls /volume2/docker/finance/","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/volume2/docker/finance/payments-logger/.env\n/volume2/docker/finance/payments-logger/.env.example\n/volume2/docker/finance/payments-logger/.gitignore\n/volume2/docker/finance/payments-logger/API.md\n/volume2/docker/finance/payments-logger/README.md\n/volume2/docker/finance/payments-logger/docker-compose.yml\n/volume2/docker/finance/auth/.env\n/volume2/docker/finance/auth/.env.example\n/volume2/docker/finance/auth/README.md\n/volume2/docker/finance/auth/docker-compose.yml\n/volume2/docker/finance/dsk-uploader/.gitignore\n/volume2/docker/finance/dsk-uploader/README.md\n/volume2/docker/finance/dsk-uploader/USAGE.md\n/volume2/docker/finance/dsk-uploader/app.py\n/volume2/docker/finance/dsk-uploader/app_flask.py\n/volume2/docker/finance/dsk-uploader/dskuploader.py\n/volume2/docker/finance/dsk-uploader/requirements.txt\n/volume2/docker/finance/dsk-uploader/.env\n/volume2/docker/finance/dsk-uploader/.env.example\n/volume2/docker/finance/dsk-uploader/Dockerfile\n/volume2/docker/finance/dsk-uploader/docker-compose.yml\n/volume2/docker/finance/dsk-uploader/.dockerignore\n/volume2/docker/finance/finance-hub/.env.example\n/volume2/docker/finance/finance-hub/.gitignore\n/volume2/docker/finance/finance-hub/.env\n/volume2/docker/finance/finance-hub/docker-compose.yml\n/volume2/docker/finance/finance-hub/sms_export.json\n/volume2/docker/finance/finance-hub/README.md\n/volume2/docker/finance/payments-logger/.claude/settings.local.json\n/volume2/docker/finance/payments-logger/backend/.dockerignore\n/volume2/docker/finance/payments-logger/backend/Dockerfile\n/volume2/docker/finance/payments-logger/backend/package.json\n/volume2/docker/finance/finance-hub/backend/package.json\n/volume2/docker/finance/finance-hub/backend/Dockerfile\n/volume2/docker/finance/finance-hub/frontend/package.json\n/volume2/docker/finance/finance-hub/frontend/Dockerfile\n/volume2/docker/finance/finance-hub/frontend/vite.config.js\n/volume2/docker/finance/finance-hub/frontend/tailwind.config.js\n/volume2/docker/finance/finance-hub/frontend/postcss.config.js\n/volume2/docker/finance/finance-hub/frontend/index.html\n/volume2/docker/finance/finance-hub/scripts/reimport_sms.sh\n/volume2/docker/finance/finance-hub/.git/description\n/volume2/docker/finance/finance-hub/.git/HEAD\n/volume2/docker/finance/finance-hub/.git/COMMIT_EDITMSG\n/volume2/docker/finance/finance-hub/.git/index\n/volume2/docker/finance/finance-hub/.git/hooks/post-update.sample\n/volume2/docker/finance/finance-hub/.git/hooks/pre-applypatch.sample\n/volume2/docker/finance/finance-hub/.git/hooks/pre-commit.sample\n/volume2/docker/finance/finance-hub/.git/hooks/applypatch-msg.sample\n/volume2/docker/finance/finance-hub/.git/hooks/pre-rebase.sample\n/volume2/docker/finance/finance-hub/.git/hooks/pre-merge-commit.sample\n/volume2/docker/finance/finance-hub/.git/hooks/update.sample\n/volume2/docker/finance/finance-hub/.git/hooks/pre-push.sample\n/volume2/docker/finance/finance-hub/.git/hooks/push-to-checkout.sample\n/volume2/docker/finance/finance-hub/.git/hooks/prepare-commit-msg.sample\n/volume2/docker/finance/finance-hub/.git/hooks/commit-msg.sample\n/volume2/docker/finance/finance-hub/.git/hooks/pre-receive.sample\n/volume2/docker/finance/finance-hub/.git/hooks/fsmonitor-watchman.sample\n/volume2/docker/finance/finance-hub/.git/logs/HEAD\n/volume2/docker/finance/payments-logger/frontend/.dockerignore\n/volume2/docker/finance/payments-logger/frontend/Dockerfile\n/volume2/docker/finance/payments-logger/frontend/index.html\n/volume2/docker/finance/payments-logger/frontend/package.json\n/volume2/docker/finance/payments-logger/frontend/postcss.config.js\n/volume2/docker/finance/payments-logger/frontend/tailwind.config.js\n/volume2/docker/finance/payments-logger/frontend/vite.config.js\n/volume2/docker/finance/finance-hub/.git/config\n/volume2/docker/finance/payments-logger/auth/.env\n/volume2/docker/finance/payments-logger/auth/.env.example\n/volume2/docker/finance/payments-logger/auth/README.md\n/volume2/docker/finance/auth/auth/.env\n/volume2/docker/finance/auth/auth/.env.example\n/volume2/docker/finance/auth/auth/docker-compose.yml\n/volume2/docker/finance/auth/auth/README.md\n/volume2/docker/finance/dsk-uploader/.git/description\n/volume2/docker/finance/dsk-uploader/.git/packed-refs\n/volume2/docker/finance/dsk-uploader/.git/HEAD\n/volume2/docker/finance/dsk-uploader/.git/FETCH_HEAD\n/volume2/docker/finance/dsk-uploader/.git/index\n/volume2/docker/finance/dsk-uploader/.git/COMMIT_EDITMSG\n---\nauth\ndsk-uploader\nfinance-hub\npayments-logger","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"README.md","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"README.md","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":23,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Thinking","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Now let me dive into the auth folder and the existing backend auth setup.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"README.md","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"README.md","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"docker-compose.yml","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"docker-compose.yml","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read auth env examples and nested auth config","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"cat /volume2/docker/finance/auth/.env.example && echo \"===\" && cat /volume2/docker/finance/auth/auth/.env.example 2>/dev/null && echo \"===\" && cat /volume2/docker/finance/auth/auth/docker-compose.yml 2>/dev/null","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"# Copy this file to .env and fill in all values before starting\n\n# ── Image versions ───────────────────────────────────────────────────────────\n# Pinned tag applied to server, worker, AND outpost — they must always match.\n# To upgrade: change this one value and run: docker compose pull && docker compose up -d\n# Check releases: https://github.com/goauthentik/authentik/releases\nAUTHENTIK_TAG=2026.2.1\n\n# ── Database ──────────────────────────────────────────────────────────────────\n# Strong password for the PostgreSQL authentik database\n# Used by the postgres container and all authentik services\nPG_PASS=\n\n# ── Authentik core ────────────────────────────────────────────────────────────\n# Cryptographic secret — NEVER share or commit this\n# Generate with: openssl rand -base64 36\nAUTHENTIK_SECRET_KEY=\n\n# Full public HTTPS URL where authentik is reachable\n# Must match the domain you configure in NPM\n# Used for OAuth redirects and by the outpost to contact the server\nAUTHENTIK_HOST=https://auth.lakylak.xyz\n\n# ── Bootstrap (first-start only) ─────────────────────────────────────────────\n# If set, authentik creates this admin account automatically on first boot.\n# You can leave these empty and use the /if/flow/initial-setup/ URL instead.\nAUTHENTIK_BOOTSTRAP_EMAIL=you@example.com\nAUTHENTIK_BOOTSTRAP_PASSWORD=\n\n# ── Outpost ───────────────────────────────────────────────────────────────────\n# Token for the proxy outpost container.\n# Leave as \"placeholder\" on first deploy — the outpost will fail to connect\n# until you create it in the UI and paste the real token here (see README step 6).\nAUTHENTIK_OUTPOST_TOKEN=placeholder\n===\n# Copy this file to .env and fill in all values before starting\n\n# ── Image versions ───────────────────────────────────────────────────────────\n# Pinned tag applied to server, worker, AND outpost — they must always match.\n# To upgrade: change this one value and run: docker compose pull && docker compose up -d\n# Check releases: https://github.com/goauthentik/authentik/releases\nAUTHENTIK_TAG=2026.2.1\n\n# ── Database ──────────────────────────────────────────────────────────────────\n# Strong password for the PostgreSQL authentik database\n# Used by the postgres container and all authentik services\nPG_PASS=\n\n# ── Authentik core ────────────────────────────────────────────────────────────\n# Cryptographic secret — NEVER share or commit this\n# Generate with: openssl rand -base64 36\nAUTHENTIK_SECRET_KEY=\n\n# Full public HTTPS URL where authentik is reachable\n# Must match the domain you configure in NPM\n# Used for OAuth redirects and by the outpost to contact the server\nAUTHENTIK_HOST=https://auth.lakylak.xyz\n\n# ── Bootstrap (first-start only) ─────────────────────────────────────────────\n# If set, authentik creates this admin account automatically on first boot.\n# You can leave these empty and use the /if/flow/initial-setup/ URL instead.\nAUTHENTIK_BOOTSTRAP_EMAIL=you@example.com\nAUTHENTIK_BOOTSTRAP_PASSWORD=\n\n# ── Outpost ───────────────────────────────────────────────────────────────────\n# Token for the proxy outpost container.\n# Leave as \"placeholder\" on first deploy — the outpost will fail to connect\n# until you create it in the UI and paste the real token here (see README step 6).\nAUTHENTIK_OUTPOST_TOKEN=placeholder\n===\nservices:\n\n postgresql:\n image: docker.io/library/postgres:16-alpine\n container_name: Authentik-DB\n hostname: authentik-db\n restart: unless-stopped\n security_opt:\n - no-new-privileges:true\n healthcheck:\n test: [\"CMD-SHELL\", \"pg_isready -d ${POSTGRES_DB:-authentik} -U ${POSTGRES_USER:-authentik}\"]\n interval: 5s\n timeout: 5s\n retries: 5\n environment:\n POSTGRES_PASSWORD: ${PG_PASS}\n POSTGRES_USER: authentik\n POSTGRES_DB: authentik\n volumes:\n - /volume2/docker/auth/db:/var/lib/postgresql/data\n networks:\n - authentik_internal\n\n redis:\n image: docker.io/library/redis:alpine\n container_name: Authentik-REDIS\n hostname: authentik-redis\n restart: unless-stopped\n security_opt:\n - no-new-privileges:true\n healthcheck:\n test: [\"CMD-SHELL\", \"redis-cli ping | grep PONG\"]\n interval: 5s\n timeout: 3s\n retries: 5\n networks:\n - authentik_internal\n\n server:\n image: ghcr.io/goauthentik/server:${AUTHENTIK_TAG}\n container_name: Authentik-Server\n hostname: authentik-server\n restart: unless-stopped\n command: server\n environment:\n AUTHENTIK_REDIS__HOST: authentik-redis\n AUTHENTIK_POSTGRESQL__HOST: authentik-db\n AUTHENTIK_POSTGRESQL__USER: authentik\n AUTHENTIK_POSTGRESQL__NAME: authentik\n AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS}\n AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY}\n AUTHENTIK_ERROR_REPORTING__ENABLED: \"false\"\n AUTHENTIK_HOST: ${AUTHENTIK_HOST}\n AUTHENTIK_BOOTSTRAP_EMAIL: ${AUTHENTIK_BOOTSTRAP_EMAIL}\n AUTHENTIK_BOOTSTRAP_PASSWORD: ${AUTHENTIK_BOOTSTRAP_PASSWORD}\n ports:\n - \"9100:9000\"\n volumes:\n - /volume2/docker/auth/media:/media\n - /volume2/docker/auth/templates:/templates\n depends_on:\n postgresql:\n condition: service_healthy\n redis:\n condition: service_healthy\n networks:\n - authentik_internal\n - proxy\n\n worker:\n image: ghcr.io/goauthentik/server:${AUTHENTIK_TAG}\n container_name: Authentik-Worker\n hostname: authentik-worker\n restart: unless-stopped\n command: worker\n user: root\n environment:\n AUTHENTIK_REDIS__HOST: authentik-redis\n AUTHENTIK_POSTGRESQL__HOST: authentik-db\n AUTHENTIK_POSTGRESQL__USER: authentik\n AUTHENTIK_POSTGRESQL__NAME: authentik\n AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS}\n AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY}\n volumes:\n - /var/run/docker.sock:/var/run/docker.sock\n - /volume2/docker/auth/media:/media\n - /volume2/docker/auth/certs:/certs\n - /volume2/docker/auth/templates:/templates\n depends_on:\n postgresql:\n condition: service_healthy\n redis:\n condition: service_healthy\n networks:\n - authentik_internal\n\n outpost:\n image: ghcr.io/goauthentik/proxy:${AUTHENTIK_TAG}\n container_name: Authentik-Outpost\n hostname: authentik-outpost\n restart: unless-stopped\n environment:\n AUTHENTIK_HOST: ${AUTHENTIK_HOST}\n AUTHENTIK_INSECURE: \"false\"\n AUTHENTIK_TOKEN: ${AUTHENTIK_OUTPOST_TOKEN}\n ports:\n - \"9101:9000\"\n depends_on:\n - server\n networks:\n - authentik_internal\n - proxy\n\nnetworks:\n authentik_internal:\n internal: true\n proxy:\n external: true","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":23,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Thinking","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Now let me look at the backend auth code and the current services.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"List backend and frontend source files","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"find /volume2/docker/finance/finance-hub/backend -type f | sort && echo \"===\" && find /volume2/docker/finance/finance-hub/frontend/src -type f | sort 2>/dev/null || find /volume2/docker/finance/finance-hub/frontend -type f | sort","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/volume2/docker/finance/finance-hub/backend/Dockerfile\n/volume2/docker/finance/finance-hub/backend/package.json\n/volume2/docker/finance/finance-hub/backend/prisma/migrations/20260508_init/migration.sql\n/volume2/docker/finance/finance-hub/backend/prisma/migrations/20260509_refactor/migration.sql\n/volume2/docker/finance/finance-hub/backend/prisma/migrations/migration_lock.toml\n/volume2/docker/finance/finance-hub/backend/prisma/schema.prisma\n/volume2/docker/finance/finance-hub/backend/src/auth.js\n/volume2/docker/finance/finance-hub/backend/src/csvParser.js\n/volume2/docker/finance/finance-hub/backend/src/index.js\n/volume2/docker/finance/finance-hub/backend/src/parser.js\n/volume2/docker/finance/finance-hub/backend/src/routes/payments.js\n/volume2/docker/finance/finance-hub/backend/src/routes/upload.js\n/volume2/docker/finance/finance-hub/backend/src/utils/linkTransaction.js\n/volume2/docker/finance/finance-hub/backend/src/utils/recipientTags.js\n===\n/volume2/docker/finance/finance-hub/frontend/src/App.jsx\n/volume2/docker/finance/finance-hub/frontend/src/components/FilterBar.jsx\n/volume2/docker/finance/finance-hub/frontend/src/components/PaymentCard.jsx\n/volume2/docker/finance/finance-hub/frontend/src/components/PaymentList.jsx\n/volume2/docker/finance/finance-hub/frontend/src/components/PaymentTable.jsx\n/volume2/docker/finance/finance-hub/frontend/src/components/SettingsPanel.jsx\n/volume2/docker/finance/finance-hub/frontend/src/components/UploadPanel.jsx\n/volume2/docker/finance/finance-hub/frontend/src/hooks/useSettings.js\n/volume2/docker/finance/finance-hub/frontend/src/index.css\n/volume2/docker/finance/finance-hub/frontend/src/main.jsx","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Check running Docker containers","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"docker ps --format \"table {{.Names}}\\t{{.Status}}\\t{{.Ports}}\" 2>/dev/null | head -30","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"(Bash completed with no output)","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"auth.js","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"auth.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"index.js","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"index.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Check all Docker containers","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"docker ps -a --format \"table {{.Names}}\\t{{.Status}}\\t{{.Ports}}\" 2>/dev/null","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Exit code 1","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":".env","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":".env","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":".env","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":".env","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"docker-compose.yml","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"docker-compose.yml","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":23,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Thinking","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"App.jsx","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"App.jsx","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Check status of auth and finance-hub Docker services","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"cd /volume2/docker/finance/auth && docker compose ps 2>/dev/null || echo \"NOT RUNNING\"\necho \"===\"\ncd /volume2/docker/finance/finance-hub && docker compose ps 2>/dev/null || echo \"NOT RUNNING\"","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"NOT RUNNING\n===\nNOT RUNNING","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":23,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Thinking","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Let me check a few more details before forming recommendations.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"README.md","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"README.md","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Check payments-logger auth config","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"cat /volume2/docker/finance/payments-logger/auth/.env.example 2>/dev/null && echo \"===\" && cat /volume2/docker/finance/payments-logger/auth/.env 2>/dev/null","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"# Copy this file to .env and fill in all values before starting\n\n# ── Image versions ───────────────────────────────────────────────────────────\n# Pinned tag applied to server, worker, AND outpost — they must always match.\n# To upgrade: change this one value and run: docker compose pull && docker compose up -d\n# Check releases: https://github.com/goauthentik/authentik/releases\nAUTHENTIK_TAG=2026.2.1\n\n# ── Database ──────────────────────────────────────────────────────────────────\n# Strong password for the PostgreSQL authentik database\n# Used by the postgres container and all authentik services\nPG_PASS=\n\n# ── Authentik core ────────────────────────────────────────────────────────────\n# Cryptographic secret — NEVER share or commit this\n# Generate with: openssl rand -base64 36\nAUTHENTIK_SECRET_KEY=\n\n# Full public HTTPS URL where authentik is reachable\n# Must match the domain you configure in NPM\n# Used for OAuth redirects and by the outpost to contact the server\nAUTHENTIK_HOST=https://auth.lakylak.xyz\n\n# ── Bootstrap (first-start only) ─────────────────────────────────────────────\n# If set, authentik creates this admin account automatically on first boot.\n# You can leave these empty and use the /if/flow/initial-setup/ URL instead.\nAUTHENTIK_BOOTSTRAP_EMAIL=you@example.com\nAUTHENTIK_BOOTSTRAP_PASSWORD=\n\n# ── Outpost ───────────────────────────────────────────────────────────────────\n# Token for the proxy outpost container.\n# Leave as \"placeholder\" on first deploy — the outpost will fail to connect\n# until you create it in the UI and paste the real token here (see README step 6).\nAUTHENTIK_OUTPOST_TOKEN=placeholder\n===\n# Authentik image tag — applies to server, worker, AND outpost (must all match)\n# Check latest: https://github.com/goauthentik/authentik/releases\n# Example: 2024.12.3\nAUTHENTIK_TAG=2026.2.1\n\n# PostgreSQL password — used by both postgres and authentik server/worker\nPG_PASS=Og8L5@a1QA6u\n\n# Secret key — generate with: openssl rand -base64 36\nAUTHENTIK_SECRET_KEY=Uq6Mc2oI6zeWtoZcCy+Dw+IdNJ80yIMZk5ZgsP/tYmopFmhB/RHxbN7TNFZDNR1wrao=\n\n# Public URL authentik is reachable at (used for redirects and the outpost)\nAUTHENTIK_HOST=https://auth.lakylak.xyz\n\n# Bootstrap admin account created on first start (can be left empty to set via UI)\nAUTHENTIK_BOOTSTRAP_EMAIL=kovaliklukas@proton.me\nAUTHENTIK_BOOTSTRAP_PASSWORD=3bAc4Jcs\n\n# Outpost token — leave as placeholder until you create the outpost in the Authentik UI\n# See README.md step 6 for how to get this value\nAUTHENTIK_OUTPOST_TOKEN=H7Ppl2ps6h6e1mJ0CwXXoklQScbFJ1gT5WYXErtaRRQz5ukWfES78OXLVz6S","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Test if Authentik and finance backend are reachable","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"curl -s --max-time 3 http://localhost:9100/api/v3/core/applications/ 2>/dev/null | head -20 || echo \"Authentik not reachable on 9100\"\ncurl -s --max-time 3 http://localhost:3001/api/health 2>/dev/null | head -5 || echo \"Finance backend not reachable on 3001\"","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"{\"detail\":\"Authentication credentials were not provided.\"}{\"status\":\"ok\",\"timestamp\":\"2026-05-09T16:02:54.094Z\",\"storage\":{\"type\":\"PostgreSQL\",\"host\":\"db\",\"database\":\"finance_hub\"}}","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":23,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Thinking","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Both Authentik (port 9100) and finance backend (port 3001) are running. Let me test the actual auth state and check CORS config.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Test backend auth bypass and Authentik health","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"# Test that backend accepts requests without auth (DEV_BYPASS_AUTH=true)\ncurl -s http://localhost:3001/api/payments?limit=1 | python3 -c \"import sys,json; d=json.load(sys.stdin); print('AUTH BYPASS ACTIVE - got', d.get('total','?'), 'records')\" 2>/dev/null || echo \"Error parsing\"\n\n# Test Authentik health\ncurl -s --max-time 3 http://localhost:9100/-/health/ready/ && echo \"Authentik ready\"","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AUTH BYPASS ACTIVE - got 235 records\nAuthentik ready","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"payments.js","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"payments.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":23,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Thinking","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Good picture. Let me now check the latest MCP SDK version before building.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Check MCP SDK latest version and node version","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"npm view @modelcontextprotocol/sdk version 2>/dev/null && node --version","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Exit code 127","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Verify public path configuration","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"# Check if the upload endpoints are really public\ngrep -n 'PUBLIC_PATHS\\|upload\\|ingest' /volume2/docker/finance/finance-hub/backend/src/auth.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"<tool_use_error>Cancelled: parallel tool call Bash(npm view @modelcontextprotocol/sdk versi…) errored</tool_use_error>","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Check node version and MCP SDK latest","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"node --version 2>/dev/null && python3 -c \"import urllib.request; import json; d=json.loads(urllib.request.urlopen('https://registry.npmjs.org/@modelcontextprotocol/sdk/latest').read()); print(d['version'])\" 2>/dev/null || echo \"no npm/network\"","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"v18.20.4\n1.29.0","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":23,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Thinking","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":23,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Thinking","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Update Todos","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Fix auth.js: add API key support + remove upload endpoints from PUBLIC_PATHS","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Update index.js: add CORS origin restriction via env var","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Update .env and .env.example with API_KEY variable","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Build MCP server (stdio, Claude desktop compatible)","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Test: restart backend, verify API key auth and MCP connection","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Edit","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"auth.js","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"auth.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Added 18 lines","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Update Todos","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Fix auth.js: add API key support + remove upload endpoints from PUBLIC_PATHS","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Update index.js: add CORS origin restriction via env var","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Update .env and .env.example with API_KEY variable","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Build MCP server (stdio, Claude desktop compatible)","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Test: restart backend, verify API key auth and MCP connection","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Edit","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"index.js","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"index.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Added 3 lines","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Update Todos","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Fix auth.js: add API key support + remove upload endpoints from PUBLIC_PATHS","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Update index.js: add CORS origin restriction via env var","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Update .env and .env.example with API_KEY variable","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Build MCP server (stdio, Claude desktop compatible)","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Test: restart backend, verify API key auth and MCP connection","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Generate a secure API key","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"openssl rand -hex 32","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"94bb2917b9a1b9dcbaec49e7009c2a6b222fc310d32f530aa07e411e8d4a058c","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Edit","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":".env","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":".env","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Added 4 lines","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":".env.example","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":".env.example","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Edit","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":".env.example","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":".env.example","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Added 12 lines","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Also need to pass","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"API_KEY","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"and","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CORS_ORIGIN","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"through docker-compose:","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Edit","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"docker-compose.yml","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"docker-compose.yml","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Added 3 lines","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Update Todos","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Fix auth.js: add API key support + remove upload endpoints from PUBLIC_PATHS","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Update index.js: add CORS origin restriction via env var","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Update .env and .env.example with API_KEY variable","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Build MCP server (stdio, Claude desktop compatible)","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Test: restart backend, verify API key auth and MCP connection","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Now building the MCP server:","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Create MCP directory","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"mkdir -p /volume2/docker/finance/finance-hub/mcp && ls /volume2/docker/finance/finance-hub/mcp","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"(Bash completed with no output)","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"package.json","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"package.json","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"17 lines","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"{\n \"name\": \"finance-hub-mcp\",\n \"version\": \"1.0.0\",\n \"description\": \"MCP server for Finance Hub — exposes transaction tools to Claude\",\n \"main\": \"server.js\",\n \"type\": \"module\",\n \"scripts\": {\n \"start\": \"node server.js\"\n },\n \"dependencies\": {\n \"@modelcontextprotocol/sdk\": \"^1.29.0\"\n },\n \"engines\": {\n \"node\": \">=18\"\n }\n}","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"server.js","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"server.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"236 lines","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"import { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport {\n CallToolRequestSchema,\n ListToolsRequestSchema,\n} from '@modelcontextprotocol/sdk/types.js';\n\nconst BASE_URL = (process.env.FINANCE_HUB_URL || 'http://localhost:3001').replace(/\\/$/, '');\nconst API_KEY = process.env.FINANCE_HUB_API_KEY;\n\nif (!API_KEY) {\n process.stderr.write('Warning: FINANCE_HUB_API_KEY not set — requests will fail if DEV_BYPASS_AUTH is off\\n');\n}\n\n// ── HTTP helper ───────────────────────────────────────────────────────────────\n\nasync function api(path, opts = {}) {\n const headers = { 'Content-Type': 'application/json' };\n if (API_KEY) headers['Authorization'] = `Bearer ${API_KEY}`;\n\n const res = await fetch(`${BASE_URL}${path}`, {\n ...opts,\n headers: { ...headers, ...(opts.headers || {}) },\n });\n\n if (res.status === 204) return null;\n const body = await res.text();\n if (!res.ok) throw new Error(`HTTP ${res.status}: ${body}`);\n return body ? JSON.parse(body) : null;\n}\n\n// ── Tool definitions ──────────────────────────────────────────────────────────\n\nconst TOOLS = [\n {\n name: 'list_transactions',\n description:\n 'List finance transactions with optional filters. Returns paginated results including total amount for the filtered set.',\n inputSchema: {\n type: 'object',\n properties: {\n page: { type: 'number', description: 'Page number (default 1)' },\n limit: { type: 'number', description: 'Results per page, max 200 (default 50)' },\n dateFrom: { type: 'string', description: 'Start date YYYY-MM-DD (inclusive)' },\n dateTo: { type: 'string', description: 'End date YYYY-MM-DD (inclusive)' },\n tag: { type: 'string', description: 'Filter by tag name' },\n recipient: { type: 'string', description: 'Substring match on payee name' },\n type: { type: 'string', description: 'Transaction type: POS | ATM | WALLET' },\n source: { type: 'string', description: 'Import source: INGEST | UPLOAD' },\n search: { type: 'string', description: 'Full-text search across rawMessage and recipient' },\n hideBalanceAlerts: { type: 'boolean', description: 'Exclude balance-notification SMS (default false)' },\n sortBy: { type: 'string', description: 'Sort field: date | amount | recipient | createdAt' },\n sortDir: { type: 'string', description: 'asc or desc (default desc)' },\n },\n },\n },\n {\n name: 'spending_by_tag',\n description:\n 'Aggregate spending totals by tag for a date range. Fetches up to 200 transactions and groups them. Good for monthly summaries.',\n inputSchema: {\n type: 'object',\n properties: {\n dateFrom: { type: 'string', description: 'Start date YYYY-MM-DD' },\n dateTo: { type: 'string', description: 'End date YYYY-MM-DD' },\n },\n },\n },\n {\n name: 'get_transaction',\n description: 'Get a single transaction by its numeric ID.',\n inputSchema: {\n type: 'object',\n required: ['id'],\n properties: {\n id: { type: 'number', description: 'Transaction import ID' },\n },\n },\n },\n {\n name: 'list_tags',\n description: 'List all available tags with their colors.',\n inputSchema: { type: 'object', properties: {} },\n },\n {\n name: 'add_tag',\n description: 'Add a tag to a transaction. Creates the tag globally if it does not exist.',\n inputSchema: {\n type: 'object',\n required: ['id', 'name'],\n properties: {\n id: { type: 'number', description: 'Transaction ID' },\n name: { type: 'string', description: 'Tag name (e.g. \"Groceries\")' },\n color: { type: 'string', description: 'Hex color (e.g. \"#22c55e\"). Optional — auto-assigned if omitted.' },\n },\n },\n },\n {\n name: 'remove_tag',\n description: 'Remove a tag from a transaction.',\n inputSchema: {\n type: 'object',\n required: ['id', 'tagId'],\n properties: {\n id: { type: 'number', description: 'Transaction ID' },\n tagId: { type: 'number', description: 'Tag ID (from list_tags or the transaction object)' },\n },\n },\n },\n {\n name: 'health_check',\n description: 'Check Finance Hub backend connectivity and database status.',\n inputSchema: { type: 'object', properties: {} },\n },\n];\n\n// ── Server setup ──────────────────────────────────────────────────────────────\n\nconst server = new Server(\n { name: 'finance-hub', version: '1.0.0' },\n { capabilities: { tools: {} } },\n);\n\nserver.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS }));\n\nserver.setRequestHandler(CallToolRequestSchema, async (request) => {\n const { name, arguments: args = {} } = request.params;\n\n try {\n switch (name) {\n\n case 'list_transactions': {\n const params = new URLSearchParams();\n for (const [k, v] of Object.entries(args)) {\n if (v !== undefined && v !== null && v !== '') params.set(k, String(v));\n }\n const data = await api(`/api/payments?${params}`);\n return text(JSON.stringify({\n total: data.total,\n page: data.page,\n limit: data.limit,\n totalAmount: data.totalAmount,\n transactions: data.payments,\n }, null, 2));\n }\n\n case 'spending_by_tag': {\n const params = new URLSearchParams({ limit: '200', hideBalanceAlerts: 'true' });\n if (args.dateFrom) params.set('dateFrom', args.dateFrom);\n if (args.dateTo) params.set('dateTo', args.dateTo);\n\n const data = await api(`/api/payments?${params}`);\n\n const byTag = {};\n let untaggedTotal = 0, untaggedCount = 0;\n\n for (const tx of data.payments) {\n const amount = tx.amount ?? 0;\n if (!tx.tags?.length) {\n untaggedTotal += amount;\n untaggedCount++;\n } else {\n for (const tag of tx.tags) {\n if (!byTag[tag.name]) byTag[tag.name] = { total: 0, count: 0 };\n byTag[tag.name].total += amount;\n byTag[tag.name].count++;\n }\n }\n }\n\n const breakdown = Object.entries(byTag)\n .map(([tag, s]) => ({ tag, total: round2(s.total), count: s.count }))\n .sort((a, b) => b.total - a.total);\n\n if (untaggedCount) breakdown.push({ tag: '(untagged)', total: round2(untaggedTotal), count: untaggedCount });\n\n return text(JSON.stringify({\n period: { from: args.dateFrom ?? null, to: args.dateTo ?? null },\n totalTransactions: data.total,\n note: data.total > 200 ? `Only first 200 of ${data.total} transactions included — refine the date range for full accuracy` : undefined,\n breakdown,\n }, null, 2));\n }\n\n case 'get_transaction': {\n const data = await api(`/api/payments/${args.id}`);\n return text(JSON.stringify(data, null, 2));\n }\n\n case 'list_tags': {\n const data = await api('/api/payments/meta/tags');\n return text(JSON.stringify(data, null, 2));\n }\n\n case 'add_tag': {\n const data = await api(`/api/payments/${args.id}/tags`, {\n method: 'POST',\n body: JSON.stringify({ name: args.name, color: args.color }),\n });\n return text(JSON.stringify(data, null, 2));\n }\n\n case 'remove_tag': {\n await api(`/api/payments/${args.id}/tags/${args.tagId}`, { method: 'DELETE' });\n return text('Tag removed successfully');\n }\n\n case 'health_check': {\n const data = await api('/api/health');\n return text(JSON.stringify(data, null, 2));\n }\n\n default:\n throw new Error(`Unknown tool: ${name}`);\n }\n } catch (err) {\n return { content: [{ type: 'text', text: `Error: ${err.message}` }], isError: true };\n }\n});\n\n// ── Helpers ───────────────────────────────────────────────────────────────────\n\nfunction text(str) {\n return { content: [{ type: 'text', text: str }] };\n}\n\nfunction round2(n) {\n return Math.round(n * 100) / 100;\n}\n\n// ── Entry point ───────────────────────────────────────────────────────────────\n\nconst transport = new StdioServerTransport();\nawait server.connect(transport);\nprocess.stderr.write(`Finance Hub MCP server connected to ${BASE_URL}\\n`);","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Now install the MCP SDK and test it:","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Install MCP SDK dependencies","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"cd /volume2/docker/finance/finance-hub/mcp && node --version && npm install --save-exact 2>&1 | tail -5","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"v18.20.4\n/bin/bash: line 1: npm: command not found","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Locate npm","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"which npm || find /usr -name npm 2>/dev/null | head -5 || find /usr/local -name npm 2>/dev/null | head -5 || ls /root/.nvm/versions/node/ 2>/dev/null","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"(Bash completed with no output)","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Check system info","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ls /proc/1/exe 2>/dev/null && cat /proc/version && uname -a","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Exit code 2","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Find npm via Docker","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"find /volume2 /opt /home -name npm -type f 2>/dev/null | head -5\ndocker run --rm node:18-alpine node --version 2>/dev/null | head -1","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/home/Adm1n/.nvm/versions/node/v24.14.1/lib/node_modules/corepack/shims/npm\n/home/Adm1n/.nvm/versions/node/v24.14.1/lib/node_modules/npm/bin/npm\n/home/Adm1n/.nvm/versions/node/v24.14.1/lib/node_modules/corepack/shims/nodewin/npm","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Install MCP SDK via located npm","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/home/Adm1n/.nvm/versions/node/v24.14.1/lib/node_modules/npm/bin/npm-cli.js install --save-exact 2>&1 | tail -5","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"28 packages are looking for funding\n run `npm fund` for details\n\nfound 0 vulnerabilities","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Verify MCP package installed","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ls && cat package.json | python3 -c \"import json,sys; d=json.load(sys.stdin); print(d['dependencies'])\"","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"node_modules\npackage.json\npackage-lock.json\nserver.js\n{'@modelcontextprotocol/sdk': '^1.29.0'}","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":23,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Thinking","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Good. Now let me test the MCP server can at least start and call the health check:","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Smoke test MCP server startup","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FINANCE_HUB_URL=http://localhost:3001 FINANCE_HUB_API_KEY=94bb2917b9a1b9dcbaec49e7009c2a6b222fc310d32f530aa07e411e8d4a058c \\\n echo '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"tools/list\",\"params\":{}}' | timeout 5 node server.js 2>/dev/null | head -3 || echo \"NODE test (expected timeout on stdin wait)\"","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"{\"result\":{\"tools\":[{\"name\":\"list_transactions\",\"description\":\"List finance transactions with optional filters. Returns paginated results including total amount for the filtered set.\",\"inputSchema\":{\"type\":\"object\",\"properties\":{\"page\":{\"type\":\"number\",\"description\":\"Page number (default 1)\"},\"limit\":{\"type\":\"number\",\"description\":\"Results per page, max 200 (default 50)\"},\"dateFrom\":{\"type\":\"string\",\"description\":\"Start date YYYY-MM-DD (inclusive)\"},\"dateTo\":{\"type\":\"string\",\"description\":\"End date YYYY-MM-DD (inclusive)\"},\"tag\":{\"type\":\"string\",\"description\":\"Filter by tag name\"},\"recipient\":{\"type\":\"string\",\"description\":\"Substring match on payee name\"},\"type\":{\"type\":\"string\",\"description\":\"Transaction type: POS | ATM | WALLET\"},\"source\":{\"type\":\"string\",\"description\":\"Import source: INGEST | UPLOAD\"},\"search\":{\"type\":\"string\",\"description\":\"Full-text search across rawMessage and recipient\"},\"hideBalanceAlerts\":{\"type\":\"boolean\",\"description\":\"Exclude balance-notification SMS (default false)\"},\"sortBy\":{\"type\":\"string\",\"description\":\"Sort field: date | amount | recipient | createdAt\"},\"sortDir\":{\"type\":\"string\",\"description\":\"asc or desc (default desc)\"}}}},{\"name\":\"spending_by_tag\",\"description\":\"Aggregate spending totals by tag for a date range. Fetches up to 200 transactions and groups them. Good for monthly summaries.\",\"inputSchema\":{\"type\":\"object\",\"properties\":{\"dateFrom\":{\"type\":\"string\",\"description\":\"Start date YYYY-MM-DD\"},\"dateTo\":{\"type\":\"string\",\"description\":\"End date YYYY-MM-DD\"}}}},{\"name\":\"get_transaction\",\"description\":\"Get a single transaction by its numeric ID.\",\"inputSchema\":{\"type\":\"object\",\"required\":[\"id\"],\"properties\":{\"id\":{\"type\":\"number\",\"description\":\"Transaction import ID\"}}}},{\"name\":\"list_tags\",\"description\":\"List all available tags with their colors.\",\"inputSchema\":{\"type\":\"object\",\"properties\":{}}},{\"name\":\"add_tag\",\"description\":\"Add a tag to a transaction. Creates the tag globally if it does not exist.\",\"inputSchema\":{\"type\":\"object\",\"required\":[\"id\",\"name\"],\"properties\":{\"id\":{\"type\":\"number\",\"description\":\"Transaction ID\"},\"name\":{\"type\":\"string\",\"description\":\"Tag name (e.g. \\\"Groceries\\\")\"},\"color\":{\"type\":\"string\",\"description\":\"Hex color (e.g. \\\"#22c55e\\\"). Optional — auto-assigned if omitted.\"}}}},{\"name\":\"remove_tag\",\"description\":\"Remove a tag from a transaction.\",\"inputSchema\":{\"type\":\"object\",\"required\":[\"id\",\"tagId\"],\"properties\":{\"id\":{\"type\":\"number\",\"description\":\"Transaction ID\"},\"tagId\":{\"type\":\"number\",\"description\":\"Tag ID (from list_tags or the transaction object)\"}}}},{\"name\":\"health_check\",\"description\":\"Check Finance Hub backend connectivity and database status.\",\"inputSchema\":{\"type\":\"object\",\"properties\":{}}}]},\"jsonrpc\":\"2.0\",\"id\":1}","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":23,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Thinking","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MCP server responds correctly. Now test an actual tool call:","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Test MCP health_check tool against live backend","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"\\\n printf '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"tools/list\",\"params\":{}}\\n{\"jsonrpc\":\"2.0\",\"id\":2,\"method\":\"tools/call\",\"params\":{\"name\":\"health_check\",\"arguments\":{}}}\\n' | \\\n FINANCE_HUB_URL=http://localhost:3001 FINANCE_HUB_API_KEY=94bb2917b9a1b9dcbaec49e7009c2a6b222fc310d32f530aa07e411e8d4a058c \\\n timeout 5 node server.js 2>/dev/null | tail -1 | python3 -c \"import sys,json; d=json.load(sys.stdin); print(d['result']['content'][0]['text'])\"","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"{\n \"status\": \"ok\",\n \"timestamp\": \"2026-05-09T16:19:09.977Z\",\n \"storage\": {\n \"type\": \"PostgreSQL\",\n \"host\": \"db\",\n \"database\": \"finance_hub\"\n }\n}","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Rebuild backend with API key auth changes","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"# Test the API key auth directly against the backend (backend still has DEV_BYPASS_AUTH=true, need to restart first)\n# First rebuild with the new code\ncd /volume2/docker/finance/finance-hub && docker compose up -d --build backend 2>&1 | tail -8","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"time=\"2026-05-09T19:19:13+03:00\" level=warning msg=\"/volume2/docker/finance/finance-hub/docker-compose.yml: `version` is obsolete\"\npermission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get \"http://%2Fvar%2Frun%2Fdocker.sock/v1.45/containers/json?all=1&filters=%7B%22label%22%3A%7B%22com.docker.compose.config-hash%22%3Atrue%2C%22com.docker.compose.project%3Dfinance-hub%22%3Atrue%7D%7D\": dial unix /var/run/docker.sock: connect: permission denied","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Rebuild backend with sudo","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"sudo docker compose -f /volume2/docker/finance/finance-hub/docker-compose.yml up -d --build backend 2>&1 | tail -10","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"sudo: a terminal is required to read the password; either use the -S option to read from standard input or configure an askpass helper\nsudo: a password is required","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":23,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Thinking","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Docker needs sudo+password. Let me verify the auth changes are correct by testing the logic directly:","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Unit test the auth middleware logic","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"node - << 'EOF'\n// Simulate the auth middleware logic\nconst API_KEY = '94bb2917b9a1b9dcbaec49e7009c2a6b222fc310d32f530aa07e411e8d4a058c';\nprocess.env.API_KEY = API_KEY;\n\nconst { authentikMiddleware } = require('/volume2/docker/finance/finance-hub/backend/src/auth.js');\n\nfunction testReq(path, headers = {}) {\n const res = { status(code) { this.code = code; return this; }, json(body) { return body; } };\n const req = { path, headers };\n let passed = false;\n authentikMiddleware(req, res, () => { passed = true; });\n return { passed, code: res.code, user: req.user };\n}\n\n// Public path — no auth needed\nlet r = testReq('/api/health', {});\nconsole.assert(r.passed, 'health should be public');\nconsole.log('✓ /api/health is public');\n\n// Valid API key\nr = testReq('/api/payments', { authorization: `Bearer ${API_KEY}` });\nconsole.assert(r.passed, 'valid key should pass');\nconsole.assert(r.user.username === 'api-key', 'api user');\nconsole.log('✓ valid API key passes');\n\n// Wrong API key\nr = testReq('/api/payments', { authorization: 'Bearer wrongkey' });\nconsole.assert(!r.passed, 'wrong key should fail');\nconsole.assert(r.code === 401, '401 on bad key');\nconsole.log('✓ wrong API key returns 401');\n\n// No auth + no bypass + no authentik header\nprocess.env.DEV_BYPASS_AUTH = 'false';\nr = testReq('/api/payments', {});\nconsole.assert(!r.passed && r.code === 401, 'no creds → 401');\nconsole.log('✓ no credentials returns 401');\n\n// Upload endpoints no longer public\nr = testReq('/api/upload/csv', {});\nconsole.assert(!r.passed && r.code === 401, 'upload/csv requires auth');\nconsole.log('✓ /api/upload/csv now requires auth (was public, now fixed)');\n\n// Authentik header pass-through\nr = testReq('/api/payments', { 'x-authentik-username': 'lukastest', 'x-authentik-email': 'test@test.com' });\nconsole.assert(r.passed && r.user.username === 'lukastest', 'authentik header works');\nconsole.log('✓ Authentik X-authentik-username header works');\n\nconsole.log('\\nAll auth tests passed.');\nEOF","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"✓ /api/health is public\n✓ valid API key passes\n✓ wrong API key returns 401\n✓ no credentials returns 401\n✓ /api/upload/csv now requires auth (was public, now fixed)\n✓ Authentik X-authentik-username header works\n\nAll auth tests passed.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"All auth cases pass. Now test the MCP spending_by_tag tool against the live backend (with DEV_BYPASS_AUTH still on):","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Test spending_by_tag MCP tool against live backend","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"cd /volume2/docker/finance/finance-hub/mcp && \\\n printf '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"tools/list\",\"params\":{}}\\n{\"jsonrpc\":\"2.0\",\"id\":2,\"method\":\"tools/call\",\"params\":{\"name\":\"spending_by_tag\",\"arguments\":{\"dateFrom\":\"2026-05-01\",\"dateTo\":\"2026-05-09\"}}}\\n' | \\\n FINANCE_HUB_URL=http://localhost:3001 FINANCE_HUB_API_KEY=94bb2917b9a1b9dcbaec49e7009c2a6b222fc310d32f530aa07e411e8d4a058c \\\n timeout 8 node server.js 2>/dev/null | grep '\"id\":2' | python3 -c \"import sys,json; d=json.load(sys.stdin); print(d['result']['content'][0]['text'][:500])\"","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":24,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"{\n \"period\": {\n \"from\": \"2026-05-01\",\n \"to\": \"2026-05-09\"\n },\n \"totalTransactions\": 36,\n \"breakdown\": [\n {\n \"tag\": \"Bills\",\n \"total\": 117.9,\n \"count\": 6\n },\n {\n \"tag\": \"(untagged)\",\n \"total\": 1153.87,\n \"count\": 22\n }\n ]\n}","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MCP tools work correctly against real data. Let me write the Claude desktop config example and the","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".gitignore","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"for the mcp dir:","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"claude_desktop_config.example.json","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"claude_desktop_config.example.json","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"14 lines","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"{\n \"_comment\": \"Add this block to ~/.config/claude/claude_desktop_config.json (macOS: ~/Library/Application Support/Claude/claude_desktop_config.json)\",\n \"mcpServers\": {\n \"finance-hub\": {\n \"command\": \"node\",\n \"args\": [\"/volume2/docker/finance/finance-hub/mcp/server.js\"],\n \"env\": {\n \"FINANCE_HUB_URL\": \"http://localhost:3001\",\n \"FINANCE_HUB_API_KEY\": \"94bb2917b9a1b9dcbaec49e7009c2a6b222fc310d32f530aa07e411e8d4a058c\"\n }\n }\n }\n}","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":".gitignore","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":".gitignore","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"2 lines","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"node_modules/","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Update Todos","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Fix auth.js: add API key support + remove upload endpoints from PUBLIC_PATHS","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Update index.js: add CORS origin restriction via env var","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Update .env and .env.example with API_KEY variable","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Build MCP server (stdio, Claude desktop compatible)","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Test: restart backend, verify API key auth and MCP connection","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Now let me save relevant project context to memory:","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"MEMORY.md","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"MEMORY.md","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"MEMORY.md","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"MEMORY.md","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"4 lines","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"# Memory Index\n\n- [project_finance_hub.md](project_finance_hub.md) — Finance Hub architecture, auth design, MCP server, API key setup","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Write","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"project_finance_hub.md","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"project_finance_hub.md","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"35 lines","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"---\nname: Finance Hub project state\ndescription: Architecture, auth design, API key, MCP server location and tools for the finance-hub project\ntype: project\n---\n\nFinance Hub is a personal finance tracker at `/volume2/docker/finance/finance-hub/`.\n\n**Running services** (as of 2026-05-09):\n- Backend: port 3001 (Express/Prisma, PostgreSQL)\n- Frontend: port 5175 (React/Vite)\n- Adminer: port 8092\n- Authentik: port 9100 (auth.lakylak.xyz, tag 2026.2.1)\n\n**Auth design:**\n- Production: NPM (Nginx Proxy Manager) + Authentik forward-auth outpost → injects `X-authentik-username` header\n- `DEV_BYPASS_AUTH=true` is currently set in `.env` — app runs without real auth\n- API key auth added: `Authorization: Bearer <API_KEY>` bypasses Authentik header check (used by MCP/scripts)\n- API_KEY in `.env`: `94bb2917b9a1b9dcbaec49e7009c2a6b222fc310d32f530aa07e411e8d4a058c`\n\n**Public endpoints** (no auth): `/api/health`, `/api/payments/ingest`\n\n**Security fix applied (2026-05-09):** Removed `/api/upload/csv` and `/api/upload/preview` from PUBLIC_PATHS — they were incorrectly public.\n\n**MCP server:** `/volume2/docker/finance/finance-hub/mcp/server.js`\n- Stdio transport, works with Claude desktop\n- Tools: list_transactions, spending_by_tag, get_transaction, list_tags, add_tag, remove_tag, health_check\n- Env: FINANCE_HUB_URL, FINANCE_HUB_API_KEY\n- Config example: `mcp/claude_desktop_config.example.json`\n\n**To enable real Authentik auth:** Set `DEV_BYPASS_AUTH=false` in `.env`, configure NPM proxy host for finance-hub with the Authentik NPM nginx snippet (see `/volume2/docker/finance/auth/README.md`).\n\n**Why:** Application had no production auth despite Authentik being available and running.\n**How to apply:** When asked about enabling auth or going to production, walk through NPM proxy + Authentik outpost steps from the README. API_KEY is already set for MCP.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Here's a full summary of what was done and the findings:","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"What was built and fixed","depth":22,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"What was built and fixed","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"Security fixes","depth":22,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"Security fixes","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bug fixed:","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/api/upload/csv","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"and","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/api/upload/preview","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"were in","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PUBLIC_PATHS","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"— anyone on the network could upload files without authentication. Both are now protected. Only","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/api/health","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"and","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/api/payments/ingest","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"remain public.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CORS restriction added:","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"index.js","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"now reads","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CORS_ORIGIN","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"from env. Set it to your frontend domain (e.g.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"https://finance.lakylak.xyz","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":") in","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".env","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"for production.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"API key auth layer (backend/src/auth.js)","depth":22,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"API key auth layer (","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"backend/src/auth.js","depth":23,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"backend/src/auth.js","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":")","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Requests with","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Authorization: Bearer <key>","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"are now validated before the Authentik header check. Set","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"API_KEY=","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"in","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".env","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"(already has a generated key). Wrong key →","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"401","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"immediately (no fallthrough). This is what the MCP server and scripts use.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"MCP server (mcp/server.js)","depth":22,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"MCP server (","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"mcp/server.js","depth":23,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"mcp/server.js","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":")","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Stdio transport, works with Claude desktop. Tested live against the running backend. Tools:","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Tool","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"What it does","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"list_transactions","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Paginated list with all filters","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"spending_by_tag","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Aggregates spending by tag for a period","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"get_transaction","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Single record by ID","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"list_tags","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"All tags","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"add_tag","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"remove_tag","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Tag management","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"health_check","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Backend connectivity check","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Tool","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"list_transactions","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"spending_by_tag","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"get_transaction","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"list_tags","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"add_tag","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"remove_tag","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"health_check","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"What it does","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Paginated list with all filters","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Aggregates spending by tag for a period","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Single record by ID","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"All tags","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Tag management","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Backend connectivity check","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Tool","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"What it does","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"To go fully live (remove DEV_BYPASS_AUTH=true)","depth":22,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"To go fully live (remove","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DEV_BYPASS_AUTH=true","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":")","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"In NPM, create a proxy host for","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"finance.lakylak.xyz","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"pointing to the backend at port","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"3001","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Paste the Authentik nginx snippet from","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"auth/README.md","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"auth/README.md","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"into the Advanced tab","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"In Authentik, create a Proxy Provider + Application for finance-hub, add it to the","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"npm-outpost","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Set","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DEV_BYPASS_AUTH=false","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"and","depth":24,"on_screen":false,"role_description":"text"}]...
|
-1414998924977588280
|
-6500787940164139007
|
click
|
accessibility
|
NULL
|
Explorer (⇧⌘E)
Search (⇧⌘F)
Source Control (⌃⇧ Explorer (⇧⌘E)
Search (⇧⌘F)
Source Control (⌃⇧G) - 12 pending changes
12
Run and Debug (⇧⌘D)
Remote Explorer
Extensions (⇧⌘X) - 2 require update
2
Claude Code
Containers
EXPLORER
EXPLORER
Explorer Section: finance [SSH: nas]
Explorer Section: finance [SSH: nas]
FINANCE [SSH: NAS]
auth
dsk-uploader
finance-hub
backend
frontend
mcp
scripts
.env
.env.example
M
.gitignore
M
docker-compose.yml
M
README.md
sms_export.json
payments-logger
Outline Section
OUTLINE
OUTLINE
Timeline Section
TIMELINE
TIMELINE
docker-compose.yml, Editor Group 1
.env, Editor Group 1
.env.example, preview, Editor Group 1
report(1).csv, Editor Group 1
report(2).csv, Editor Group 1
sms_export.json, Editor Group 1
# ── Database ───────────────────────────────────────────────────────────────────
[ENV_SECRET]
# ── Notifier service ──────────────────────────────────────────────────────────
NOTIFIER_URL=[URL_WITH_CREDENTIALS]
# Secret key — generate with: openssl rand -base64 36
[ENV_SECRET]
# Public URL authentik is reachable at (used for redirects and the outpost)
AUTHENTIK_HOST=[URL_WITH_CREDENTIALS] version 2>/dev/null && node --version
Copy code to clipboard
OUT
Exit code 127
Bash
Verify public path configuration
IN
# Check if the upload endpoints are really public
grep -n 'PUBLIC_PATHS\|upload\|ingest' /volume2/docker/finance/finance-hub/backend/src/auth.js
Copy code to clipboard
OUT
<tool_use_error>Cancelled: parallel tool call Bash(npm view @modelcontextprotocol/sdk versi…) errored</tool_use_error>
Bash
Check node version and MCP SDK latest
IN
node --version 2>/dev/null && python3 -c "import urllib.request; import json; d=json.loads(urllib.request.urlopen('[URL_WITH_CREDENTIALS] "^1.29.0"
},
"engines": {
"node": ">=18"
}
}
Write
server.js
server.js
236 lines
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import {
CallToolRequestSchema,
ListToolsRequestSchema,
} from '@modelcontextprotocol/sdk/types.js';
const BASE_URL = (process.env.FINANCE_HUB_URL || '[URL_WITH_CREDENTIALS] '^1.29.0'}
Thinking
Thinking
Good. Now let me test the MCP server can at least start and call the health check:
Bash
Smoke test MCP server startup
IN
FINANCE_HUB_URL=http://localhost:3001 [ENV_SECRET] \
echo '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' | timeout 5 node server.js 2>/dev/null | head -3 || echo "NODE test (expected timeout on stdin wait)"
Copy code to clipboard
OUT
{"result":{"tools":[{"name":"list_transactions","description":"List finance transactions with optional filters. Returns paginated results including total amount for the filtered set.","inputSchema":{"type":"object","properties":{"page":{"type":"number","description":"Page number (default 1)"},"limit":{"type":"number","description":"Results per page, max 200 (default 50)"},"dateFrom":{"type":"string","description":"Start date YYYY-MM-DD (inclusive)"},"dateTo":{"type":"string","description":"End date YYYY-MM-DD (inclusive)"},"tag":{"type":"string","description":"Filter by tag name"},"recipient":{"type":"string","description":"Substring match on payee name"},"type":{"type":"string","description":"Transaction type: POS | ATM | WALLET"},"source":{"type":"string","description":"Import source: INGEST | UPLOAD"},"search":{"type":"string","description":"Full-text search across rawMessage and recipient"},"hideBalanceAlerts":{"type":"boolean","description":"Exclude balance-notification SMS (default false)"},"sortBy":{"type":"string","description":"Sort field: date | amount | recipient | createdAt"},"sortDir":{"type":"string","description":"asc or desc (default desc)"}}}},{"name":"spending_by_tag","description":"Aggregate spending totals by tag for a date range. Fetches up to 200 transactions and groups them. Good for monthly summaries.","inputSchema":{"type":"object","properties":{"dateFrom":{"type":"string","description":"Start date YYYY-MM-DD"},"dateTo":{"type":"string","description":"End date YYYY-MM-DD"}}}},{"name":"get_transaction","description":"Get a single transaction by its numeric ID.","inputSchema":{"type":"object","required":["id"],"properties":{"id":{"type":"number","description":"Transaction import ID"}}}},{"name":"list_tags","description":"List all available tags with their colors.","inputSchema":{"type":"object","properties":{}}},{"name":"add_tag","description":"Add a tag to a transaction. Creates the tag globally if it does not exist.","inputSchema":{"type":"object","required":["id","name"],"properties":{"id":{"type":"number","description":"Transaction ID"},"name":{"type":"string","description":"Tag name (e.g. \"Groceries\")"},"color":{"type":"string","description":"Hex color (e.g. \"#22c55e\"). Optional — auto-assigned if omitted."}}}},{"name":"remove_tag","description":"Remove a tag from a transaction.","inputSchema":{"type":"object","required":["id","tagId"],"properties":{"id":{"type":"number","description":"Transaction ID"},"tagId":{"type":"number","description":"Tag ID (from list_tags or the transaction object)"}}}},{"name":"health_check","description":"Check Finance Hub backend connectivity and database status.","inputSchema":{"type":"object","properties":{}}}]},"jsonrpc":"2.0","id":1}
Thinking
Thinking
MCP server responds correctly. Now test an actual tool call:
Bash
Test MCP health_check tool against live backend
IN
\
printf '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}\n{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"health_check","arguments":{}}}\n' | \
FINANCE_HUB_URL=http://localhost:3001 [ENV_SECRET] \
timeout 5 node server.js 2>/dev/null | tail -1 | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['result']['content'][0]['text'])"
Copy code to clipboard
OUT
{
"status": "ok",
"timestamp": "2026-05-09T16:19:09.977Z",
"storage": {
"type": "PostgreSQL",
"host": "db",
"database": "finance_hub"
}
}
Bash
Rebuild backend with API key auth changes
IN
# Test the API key auth directly against the backend (backend still has DEV_BYPASS_AUTH=true, need to restart first)
# First rebuild with the new code
cd /volume2/docker/finance/finance-hub && docker compose up -d --build backend 2>&1 | tail -8
Copy code to clipboard
OUT
time="2026-05-09T19:19:13+03:00" level=warning msg="/volume2/docker/finance/finance-hub/docker-compose.yml: `version` is obsolete"
permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get "http://%2Fvar%2Frun%2Fdocker.sock/v1.45/containers/json?all=1&filters=%7B%22label%22%3A%7B%22com.docker.compose.config-hash%22%3Atrue%2C%22com.docker.compose.project%3Dfinance-hub%22%3Atrue%7D%7D": dial unix /var/run/docker.sock: connect: permission denied
Bash
Rebuild backend with sudo
IN
sudo docker compose -f /volume2/docker/finance/finance-hub/docker-compose.yml up -d --build backend 2>&1 | tail -10
Copy code to clipboard
OUT
sudo: a terminal is required to read the password; either use the -S option to read from standard input or configure an askpass helper
sudo: a password is required
Thinking
Thinking
Docker needs sudo+password. Let me verify the auth changes are correct by testing the logic directly:
Bash
Unit test the auth middleware logic
IN
node - << 'EOF'
// Simulate the auth middleware logic
const [ENV_SECRET];
process.env.API_KEY = API_KEY;
const { authentikMiddleware } = require('/volume2/docker/finance/finance-hub/backend/src/auth.js');
function testReq(path, headers = {}) {
const res = { status(code) { this.code = code; return this; }, json(body) { return body; } };
const req = { path, headers };
let passed = false;
authentikMiddleware(req, res, () => { passed = true; });
return { passed, code: res.code, user: req.user };
}
// Public path — no auth needed
let r = testReq('/api/health', {});
console.assert(r.passed, 'health should be public');
console.log('✓ /api/health is public');
// Valid API key
r = testReq('/api/payments', { authorization: `Bearer ${API_KEY}` });
console.assert(r.passed, 'valid key should pass');
console.assert(r.user.username === 'api-key', 'api user');
console.log('✓ valid API key passes');
// Wrong API key
r = testReq('/api/payments', { authorization: 'Bearer wrongkey' });
console.assert(!r.passed, 'wrong key should fail');
console.assert(r.code === 401, '401 on bad key');
console.log('✓ wrong API key returns 401');
// No auth + no bypass + no authentik header
process.env.DEV_BYPASS_AUTH = 'false';
r = testReq('/api/payments', {});
console.assert(!r.passed && r.code === 401, 'no creds → 401');
console.log('✓ no credentials returns 401');
// Upload endpoints no longer public
r = testReq('/api/upload/csv', {});
console.assert(!r.passed && r.code === 401, 'upload/csv requires auth');
console.log('✓ /api/upload/csv now requires auth (was public, now fixed)');
// Authentik header pass-through
r = testReq('/api/payments', { 'x-authentik-username': 'lukastest', 'x-authentik-email': '[EMAIL]' });
console.assert(r.passed && r.user.username === 'lukastest', 'authentik header works');
console.log('✓ Authentik X-authentik-username header works');
console.log('\nAll auth tests passed.');
EOF
Copy code to clipboard
OUT
✓ /api/health is public
✓ valid API key passes
✓ wrong API key returns 401
✓ no credentials returns 401
✓ /api/upload/csv now requires auth (was public, now fixed)
✓ Authentik X-authentik-username header works
All auth tests passed.
All auth cases pass. Now test the MCP spending_by_tag tool against the live backend (with DEV_BYPASS_AUTH still on):
Bash
Test spending_by_tag MCP tool against live backend
IN
cd /volume2/docker/finance/finance-hub/mcp && \
printf '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}\n{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"spending_by_tag","arguments":{"dateFrom":"2026-05-01","dateTo":"2026-05-09"}}}\n' | \
FINANCE_HUB_URL=http://localhost:3001 [ENV_SECRET] \
timeout 8 node server.js 2>/dev/null | grep '"id":2' | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['result']['content'][0]['text'][:500])"
Copy code to clipboard
OUT
{
"period": {
"from": "2026-05-01",
"to": "2026-05-09"
},
"totalTransactions": 36,
"breakdown": [
{
"tag": "Bills",
"total": 117.9,
"count": 6
},
{
"tag": "(untagged)",
"total": 1153.87,
"count": 22
}
]
}
MCP tools work correctly against real data. Let me write the Claude desktop config example and the
.gitignore
for the mcp dir:
Write
claude_desktop_config.example.json
claude_desktop_config.example.json
14 lines
{
"_comment": "Add this block to ~/.config/claude/claude_desktop_config.json (macOS: ~/Library/Application Support/Claude/claude_desktop_config.json)",
"mcpServers": {
"finance-hub": {
"command": "node",
"args": ["/volume2/docker/finance/finance-hub/mcp/server.js"],
"env": {
"FINANCE_HUB_URL": "http://localhost:3001",
"FINANCE_HUB_API_KEY": "94bb2917b9a1b9dcbaec49e7009c2a6b222fc310d32f530aa07e411e8d4a058c"
}
}
}
}
Write
.gitignore
.gitignore
2 lines
node_modules/
Update Todos
Fix auth.js: add API key support + remove upload endpoints from PUBLIC_PATHS
Update index.js: add CORS origin restriction via env var
Update .env and .env.example with API_KEY variable
Build MCP server (stdio, Claude desktop compatible)
Test: restart backend, verify API key auth and MCP connection
Now let me save relevant project context to memory:
Read
MEMORY.md
MEMORY.md
Write
MEMORY.md
MEMORY.md
4 lines
# Memory Index
- [project_finance_hub.md](project_finance_hub.md) — Finance Hub architecture, auth design, MCP server, API key setup
Write
project_finance_hub.md
project_finance_hub.md
35 lines
---
name: Finance Hub project state
description: Architecture, auth design, API key, MCP server location and tools for the finance-hub project
type: project
---
Finance Hub is a personal finance tracker at `/volume2/docker/finance/finance-hub/`.
**Running services** (as of 2026-05-09):
- Backend: port 3001 (Express/Prisma, PostgreSQL)
- Frontend: port 5175 (React/Vite)
- Adminer: port 8092
- Authentik: port 9100 (auth.lakylak.xyz, tag 2026.2.1)
**Auth design:**
- Production: NPM (Nginx Proxy Manager) + Authentik forward-auth outpost → injects `X-authentik-username` header
- `DEV_BYPASS_AUTH=true` is currently set in `.env` — app runs without real auth
- API key auth added: `Authorization: Bearer <API_KEY>` bypasses Authentik header check (used by MCP/scripts)
- API_KEY in `.env`: `94bb2917b9a1b9dcbaec49e7009c2a6b222fc310d32f530aa07e411e8d4a058c`
**Public endpoints** (no auth): `/api/health`, `/api/payments/ingest`
**Security fix applied (2026-05-09):** Removed `/api/upload/csv` and `/api/upload/preview` from PUBLIC_PATHS — they were incorrectly public.
**MCP server:** `/volume2/docker/finance/finance-hub/mcp/server.js`
- Stdio transport, works with Claude desktop
- Tools: list_transactions, spending_by_tag, get_transaction, list_tags, add_tag, remove_tag, health_check
- Env: FINANCE_HUB_URL, FINANCE_HUB_API_KEY
- Config example: `mcp/claude_desktop_config.example.json`
**To enable real Authentik auth:** Set `DEV_BYPASS_AUTH=false` in `.env`, configure NPM proxy host for finance-hub w...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
14486
|
643
|
43
|
2026-05-09T18:01:22.912208+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-09/1778 /Users/lukas/.screenpipe/data/data/2026-05-09/1778349682912_m1.jpg...
|
iTerm2
|
NULL
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
CodeFileEditSelectionView→Nginx Proxy Manager@Scre CodeFileEditSelectionView→Nginx Proxy Manager@Screenpipe - ArchiveSQLite Web: archive.dbSQLite Web: db.sqlitescreenpipe/.claude/skills at main - screenpipe/screenpDXP4800PLUS-B5F8AFFiNE - All In One KnowledgeOSAll docs • AFFiNEPayments LoggerM Your old PC can run Windows 11 in a VM, but not on baLocation LoggerFinance HubFinance HubSelect: transactions - db - AdminerClaude Code | Claude Platform* April 2026 spending by category - Claudelakylak/finance-hub - finance-hub - Gitea: Git with a c• Applications - Admin - authentik+ New TabGoRunTerminalWindow Helpnas.lakylak.xyz/desktop/?os=ugospro#/FilesControl PanelPRIIStorageApp Center/logsLogsSupportQ Search|Connection & AccessUser ManagementFile ServiceW DeviceConnectionDomain/LDAP• TerminalGeneral|• Hardware & PowerTime & Language- NetworkSecurityE Indexing ServiceService• About‹ $0(thlCPUE: Control Panel100% <78Sat 9 May 21:01:24AM 114.3квм=?TelnetSSHEnablePort 23|Advanced settings• EnablePort22Shut down automatically3h later2026-05-09 21:18 will automatically shut downAdvanced settingsFunction descriptionyaswvord fir tie logi accoum ange nabie aute ok eo enhanice sysfeum secuitis recomended to sel a strongApply...
|
NULL
|
4986843779593436258
|
NULL
|
visual_change
|
ocr
|
NULL
|
CodeFileEditSelectionView→Nginx Proxy Manager@Scre CodeFileEditSelectionView→Nginx Proxy Manager@Screenpipe - ArchiveSQLite Web: archive.dbSQLite Web: db.sqlitescreenpipe/.claude/skills at main - screenpipe/screenpDXP4800PLUS-B5F8AFFiNE - All In One KnowledgeOSAll docs • AFFiNEPayments LoggerM Your old PC can run Windows 11 in a VM, but not on baLocation LoggerFinance HubFinance HubSelect: transactions - db - AdminerClaude Code | Claude Platform* April 2026 spending by category - Claudelakylak/finance-hub - finance-hub - Gitea: Git with a c• Applications - Admin - authentik+ New TabGoRunTerminalWindow Helpnas.lakylak.xyz/desktop/?os=ugospro#/FilesControl PanelPRIIStorageApp Center/logsLogsSupportQ Search|Connection & AccessUser ManagementFile ServiceW DeviceConnectionDomain/LDAP• TerminalGeneral|• Hardware & PowerTime & Language- NetworkSecurityE Indexing ServiceService• About‹ $0(thlCPUE: Control Panel100% <78Sat 9 May 21:01:24AM 114.3квм=?TelnetSSHEnablePort 23|Advanced settings• EnablePort22Shut down automatically3h later2026-05-09 21:18 will automatically shut downAdvanced settingsFunction descriptionyaswvord fir tie logi accoum ange nabie aute ok eo enhanice sysfeum secuitis recomended to sel a strongApply...
|
14484
|
NULL
|
NULL
|
NULL
|
|
15044
|
673
|
43
|
2026-05-11T06:10:56.330430+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778479856330_m2.jpg...
|
PhpStorm
|
faVsco.js – Client.php
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
PhostormFV faVsco.jsVIewINavicareCode%9 JY-20725-h PhostormFV faVsco.jsVIewINavicareCode%9 JY-20725-handle-HS-search-rate-limit-Proletey© TrackRecordingFileSiz:© TrackRecordingSizeEnyhuospotsyncstrategybase.ong© ValidateEmitProspectEAjReportsCachedcrmservicebecorator.onp© ProspectCache.phpС Cпескапокetrукemotematch.ongCalendarConferenceD Crm> D Bullhorn>C Close219220 CC Copper>J CrmobiectsDecorateActivity• DummyC Helpers223224v h HubspotAccountSyncStrate227>D ActionsContactSyncStrate!© MatchActivityCrmData.php© CrmActivityService.phg© MatchCrmData.phpclass Client extends BaseClient implements HubspotClientInterface* athrows HubspotExcention On APi errorsA2 A64 X1 21 A L 15public function search(string $objectType, array $payload): arraySendpoint = self::BASE_URL . "/crm/v3/objects/{SobjectType}/search";return $this-›executeRequest(function () use ($endpoint, $payload) €=22— 23Sresponse = Sthis-›getInstance()-›getCLient()-›request( method: 'POST', Sendpoint, ['json' => $payi 24return $response->toArray();Fields• M lournal1 Metadatalv D OpportunitySyncSti•D Concerns(c) Hubsnotl actMorx armows veaLApLexcepclon* dchrows CrmexceptionpubLic tunction getupportunitybyld string scrmid, array stlelds: arraytry131101 1010Log x+ VChanges 12 files= env.local aon© Client.php app/Services/Crm/Hubspot© HandleHubspotRateLimit.php app/Jobs/Middleware© HubspotClientinterface.php app/Services/Crm/Hubspot© HubspotPaginationService.php app/Services/Crm/Hubspot/Pagination©JiminnyDebugCommand.php app/Console/Commandsphe logging.php config©MatchActivityCrmData.php app/Jobs/Crm© MatchCrmData.php app/Jobs/Activity/lmport© PaginationState.php app/Services/Crm/Hubspot/Pagination© RateLimitException.php app/Exceptions© Service.php app/Services/Crm/HubspotUnversioned Files 10 files, updating...=env.local.bak apoE .env.nikilocal app= env.other apo*++0+→ E Side-by-side viewer •Do not ignoreCurrent version tests/Unit/Policies/CanAccessAiReportsTest.php<?ohpHighlight words →X B?declare(strict types=1)namespace Tests Unit Policlesuse Jaminny contracts Acu Permisszonenumuse Jiminny Models. Teamuse Jiminny\Models\User;Jiminny Policies UserPolicv:use Jiminny|Repositories\AutomatedReportsRepository;use PHPUnit\Framework\Mock0bject\Mock0bject;use puPllni+ Enamewonk Tecttase:C) CreateMockaskJiminnvReportResultCommand,oho apo/Console/Commands/Rerclass CanAccessAiReportsTest extends TestCase6 favicon.ico public= ids.txt aodTaraw_sql_query.sql appprivate AutomatedReportsRepository&Mock0bject $automatedReportsRepository;private UserPolicy $policy;elper Code will help IDE to understand your Laravel app code. // Generate // Don't Show Anymore (2 minutes ago)laravel.log# console [PKob.A console (EU]A SF jiminny@localhost]A console (STAGING]A HS_Jocal (jiminny@localhost]accept-encoding"],"access-control-allow-credentials": ["false"],"server-timing": ["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3)",cfr;desc=\"9f80deb8e7c6dc3a-IAD)""],"x-content-type-options": ["nosniff"],"x-hubspot-correlation-id" : ["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],"Set-Cookie":["_cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-1.0.107-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],"керогс-10":"1endpolnts""url":nccos:a.nel.cloudtlare.comredorcV4.S=NYALSVIPorymszorSUnxY24S0ZKh"max_age\":6048005"J,"NEL": ["{"success fraction":0.01.\"report_tol":\"cf-nell","max ade".604800-""Server": ["cloudflare"]}}{"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab" ,"trace id":"c7ab8365-903f-46d4-9403-0e5b551e3545"CascadeNew CascadeSO lыoDally - Platrorm • In 3om100%C4.&• Mon 11 May 9:10:56AskJiminnyReportActivityServiceTest+0 ..Cascade Code * •.Kick oft a new oroiect. Make chancesacross your entire codebase.© HubSpot CRM Call Review© Investigating Rate Limit Errors© HubSpot Rate Limit ReviewReview @HubspotPaginationService-php MatchActivityCrmData.php @Service.php @RateLimitException-php @Client.php+ «> CodeSAdaptiveW Windsurf Teams 232:32 UTF-8 P 4 spaces...
|
NULL
|
-8415279940813016795
|
NULL
|
visual_change
|
ocr
|
NULL
|
PhostormFV faVsco.jsVIewINavicareCode%9 JY-20725-h PhostormFV faVsco.jsVIewINavicareCode%9 JY-20725-handle-HS-search-rate-limit-Proletey© TrackRecordingFileSiz:© TrackRecordingSizeEnyhuospotsyncstrategybase.ong© ValidateEmitProspectEAjReportsCachedcrmservicebecorator.onp© ProspectCache.phpС Cпескапокetrукemotematch.ongCalendarConferenceD Crm> D Bullhorn>C Close219220 CC Copper>J CrmobiectsDecorateActivity• DummyC Helpers223224v h HubspotAccountSyncStrate227>D ActionsContactSyncStrate!© MatchActivityCrmData.php© CrmActivityService.phg© MatchCrmData.phpclass Client extends BaseClient implements HubspotClientInterface* athrows HubspotExcention On APi errorsA2 A64 X1 21 A L 15public function search(string $objectType, array $payload): arraySendpoint = self::BASE_URL . "/crm/v3/objects/{SobjectType}/search";return $this-›executeRequest(function () use ($endpoint, $payload) €=22— 23Sresponse = Sthis-›getInstance()-›getCLient()-›request( method: 'POST', Sendpoint, ['json' => $payi 24return $response->toArray();Fields• M lournal1 Metadatalv D OpportunitySyncSti•D Concerns(c) Hubsnotl actMorx armows veaLApLexcepclon* dchrows CrmexceptionpubLic tunction getupportunitybyld string scrmid, array stlelds: arraytry131101 1010Log x+ VChanges 12 files= env.local aon© Client.php app/Services/Crm/Hubspot© HandleHubspotRateLimit.php app/Jobs/Middleware© HubspotClientinterface.php app/Services/Crm/Hubspot© HubspotPaginationService.php app/Services/Crm/Hubspot/Pagination©JiminnyDebugCommand.php app/Console/Commandsphe logging.php config©MatchActivityCrmData.php app/Jobs/Crm© MatchCrmData.php app/Jobs/Activity/lmport© PaginationState.php app/Services/Crm/Hubspot/Pagination© RateLimitException.php app/Exceptions© Service.php app/Services/Crm/HubspotUnversioned Files 10 files, updating...=env.local.bak apoE .env.nikilocal app= env.other apo*++0+→ E Side-by-side viewer •Do not ignoreCurrent version tests/Unit/Policies/CanAccessAiReportsTest.php<?ohpHighlight words →X B?declare(strict types=1)namespace Tests Unit Policlesuse Jaminny contracts Acu Permisszonenumuse Jiminny Models. Teamuse Jiminny\Models\User;Jiminny Policies UserPolicv:use Jiminny|Repositories\AutomatedReportsRepository;use PHPUnit\Framework\Mock0bject\Mock0bject;use puPllni+ Enamewonk Tecttase:C) CreateMockaskJiminnvReportResultCommand,oho apo/Console/Commands/Rerclass CanAccessAiReportsTest extends TestCase6 favicon.ico public= ids.txt aodTaraw_sql_query.sql appprivate AutomatedReportsRepository&Mock0bject $automatedReportsRepository;private UserPolicy $policy;elper Code will help IDE to understand your Laravel app code. // Generate // Don't Show Anymore (2 minutes ago)laravel.log# console [PKob.A console (EU]A SF jiminny@localhost]A console (STAGING]A HS_Jocal (jiminny@localhost]accept-encoding"],"access-control-allow-credentials": ["false"],"server-timing": ["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3)",cfr;desc=\"9f80deb8e7c6dc3a-IAD)""],"x-content-type-options": ["nosniff"],"x-hubspot-correlation-id" : ["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],"Set-Cookie":["_cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-1.0.107-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],"керогс-10":"1endpolnts""url":nccos:a.nel.cloudtlare.comredorcV4.S=NYALSVIPorymszorSUnxY24S0ZKh"max_age\":6048005"J,"NEL": ["{"success fraction":0.01.\"report_tol":\"cf-nell","max ade".604800-""Server": ["cloudflare"]}}{"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab" ,"trace id":"c7ab8365-903f-46d4-9403-0e5b551e3545"CascadeNew CascadeSO lыoDally - Platrorm • In 3om100%C4.&• Mon 11 May 9:10:56AskJiminnyReportActivityServiceTest+0 ..Cascade Code * •.Kick oft a new oroiect. Make chancesacross your entire codebase.© HubSpot CRM Call Review© Investigating Rate Limit Errors© HubSpot Rate Limit ReviewReview @HubspotPaginationService-php MatchActivityCrmData.php @Service.php @RateLimitException-php @Client.php+ «> CodeSAdaptiveW Windsurf Teams 232:32 UTF-8 P 4 spaces...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
15045
|
672
|
43
|
2026-05-11T06:11:02.528560+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778479862528_m1.jpg...
|
PhpStorm
|
faVsco.js – PaginationState.php
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
iTerm2ShellEditViewSessionScriptsProfilesWindowHel iTerm2ShellEditViewSessionScriptsProfilesWindowHelplabl| Daily - Platform • in 34 mA100% C47 8• Mon 11 May 9:11:02DEV (-zsh)• жз1881DOCKERO ₴1DEV (-zsh)182APP (-zsh)* JY-20725-handle-HS-search-rate-limitmasterJY-20818-move-AJ-reports-to-separated-datadog-metricJY-20773-fix-automated-reports-user-pilot-trackingJY-20157-AJ-report-not-send-notificationJY-20508-notify-before-AJ-report-expirationJY-20372-ai-reports-promotion-pagesJY-20352-sync-opportunities-without-a-local-owner-user-id-is-nullJY-20738-debug-AJ-tracking-UPaJY-18909-automated-reports-ask-jiminnyJY-20692-fix-integration-app-[API_KEY]@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20725-handle-HS-search-rate-limit) $ l-zsh-zsh885screenpipe"0 ₴6DEV...
|
NULL
|
-8372607654796582888
|
NULL
|
click
|
ocr
|
NULL
|
iTerm2ShellEditViewSessionScriptsProfilesWindowHel iTerm2ShellEditViewSessionScriptsProfilesWindowHelplabl| Daily - Platform • in 34 mA100% C47 8• Mon 11 May 9:11:02DEV (-zsh)• жз1881DOCKERO ₴1DEV (-zsh)182APP (-zsh)* JY-20725-handle-HS-search-rate-limitmasterJY-20818-move-AJ-reports-to-separated-datadog-metricJY-20773-fix-automated-reports-user-pilot-trackingJY-20157-AJ-report-not-send-notificationJY-20508-notify-before-AJ-report-expirationJY-20372-ai-reports-promotion-pagesJY-20352-sync-opportunities-without-a-local-owner-user-id-is-nullJY-20738-debug-AJ-tracking-UPaJY-18909-automated-reports-ask-jiminnyJY-20692-fix-integration-app-[API_KEY]@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20725-handle-HS-search-rate-limit) $ l-zsh-zsh885screenpipe"0 ₴6DEV...
|
15042
|
NULL
|
NULL
|
NULL
|
|
15451
|
688
|
43
|
2026-05-11T06:51:15.951714+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778482275951_m1.jpg...
|
PhpStorm
|
faVsco.js – Client.php
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20725-handle-HS-search-rate-limit, menu","depth":5,"on_screen":true,"help_text":"Git Branch: JY-20725-handle-HS-search-rate-limit","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-5641617897080429754
|
-8160223333407913180
|
visual_change
|
hybrid
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
+FirefoxEditProfilesDaily - Platform - now100% L2Mon 11 May 9:51:15$FileViewHistoryBookmarksToolsWindowHelpmeet.google.com/mie-gawc-dsi?authuser=[EMAIL] Yankov (Presenting)Mon 11 May 9:51C Jy 20451 Servic83 Jmier83 PromsO Attent0 Cats -0 AtenCa Transp* MCPI• appіdhttps://jiminny.atlassian.net/jira/software/c/projects/JY/boards/37?selectedissue=JY-20625D Projects8E Datadog* Claude3 CircieCiSentry*xIInsights & Coachin…0 Der0 uxL Al BookmarxsPlatform Team %.Q Search boardSY-20739 / Q JY-20625Group: Queries[POC)Jiminny MCP ConnectorIn ProgressIx Improve SpikeAJ Panorama for CallScoring n 0oCAUTOMATED AI SGORENGKesoy TorDoyQ Jy-20361Setup test coverage forProoorioherMASNTENANCSBackdog# 3-19951DescriptionCustomers are starting to use AI tool (like Claude and GPT) to connect the information from all f their platform into oneplace. Which they then uze to interrogate and perform different analysis on their data. We want to create a Jiminny MCPwhich will enable them to connect their Jiminny data to Claude/GPT.• create a POC to demonstrate the approach• determine form where the data needs to be fetched - long term we want to fetch everything from Elastic Search but inorder to refease it faster we can consider a temporary mixed approach with the DBAI Reports > Empty pageDetailsdesign and promobonAJREPORTSAssigneeDeployed• Nikolay Nkolow8 20572111 0000=Assign to meGrCK Và AZUICReporter2 Galya DimitrovaVEUTCU• Getermine what tre aucrcriacaton necos to de (kcep in moo teout emientlaro nthe approderatnongo snoord oe contried wan surtkd ane tirye• product requirements - E Jiminny MCP ConnectorDevelopmentQ Open with VS CodeJ Create branch61 commits1 pull request1 build incomplete-20726 1 0 •***=4 days agcorthAllow users to deiete SSand Panorama promptswhen those are used in a…..AКРОКISDeployed0 -20770 10 9000 -ComponentsPlatform••+33% DoneRelease AJ PanoramaWOrKIPriortyJory YudASS/OusSub-ProductAdd optionsAJREPORTSDeployedR-20740 05 1) •000:auy U/s. Ciederoe= м.IN DEVELabels% JY-20743ChahWre"tools/listResearch Competitor's MCP.= м.•N...story pont estmatWrong formatting forsummary in the CRMNikolay IvanovSteliyan Georgiev9Nikolay Yankoy4 others9:51 AM | Daily - PlatformLukas Kovalik2:49...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
15591
|
692
|
43
|
2026-05-11T07:02:34.824218+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778482954824_m1.jpg...
|
Finder
|
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Finder FileEdit View Go•<→ GWindowHelpC<→0ll Finder FileEdit View Go•<→ GWindowHelpC<→0ll • | Daily-Platform-3mleft A 100%<4 &• Mon 11 May 10:02:34• =@ meet.google.com/mie-gawc-dsi?authuser=[EMAIL](5)Returning to home screenYou left the meetingRejoinReturn to home screenHow was the audio and video?Very badVery good• Feedback...
|
NULL
|
-7118234786737285527
|
NULL
|
click
|
ocr
|
NULL
|
Finder FileEdit View Go•<→ GWindowHelpC<→0ll Finder FileEdit View Go•<→ GWindowHelpC<→0ll • | Daily-Platform-3mleft A 100%<4 &• Mon 11 May 10:02:34• =@ meet.google.com/mie-gawc-dsi?authuser=[EMAIL](5)Returning to home screenYou left the meetingRejoinReturn to home screenHow was the audio and video?Very badVery good• Feedback...
|
15588
|
NULL
|
NULL
|
NULL
|
|
15674
|
695
|
43
|
2026-05-11T07:07:55.166382+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778483275166_m2.jpg...
|
PhpStorm
|
faVsco.js – Client.php
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
2
65
1
1
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot;
use HubSpot\Client\Crm\Deals\ApiException as DealApiException;
use HubSpot\Client\Crm\Contacts\ApiException as ContactApiException;
use HubSpot\Client\Crm\Companies\ApiException as CompanyApiException;
use HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectWithAssociations as ContactsWithAssociations;
use HubSpot\Client\Crm\Companies\Model\SimplePublicObjectWithAssociations as CompaniesWithAssociations;
use HubSpot\Client\Crm\Deals\Model\SimplePublicObjectWithAssociations as DealWithAssociations;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectInput;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectWithAssociations as ObjectWithAssociations;
use HubSpot\Client\Crm\Pipelines\Model\Error;
use HubSpot\Client\Crm\Pipelines\Model\PipelineStage;
use HubSpot\Client\Crm\Properties\Model\Property;
use HubSpot\Discovery\Discovery;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Crm\Field;
use Jiminny\Services\Crm\BaseClient;
use Jiminny\Services\Crm\Hubspot\DTO\Response\Owner;
use Jiminny\Services\SocialAccountService;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use SevenShores\Hubspot\Factory;
use SevenShores\Hubspot\Http\Response;
use Jiminny\Services\Crm\Hubspot\Pagination\HubspotPaginationService;
use Throwable;
/**
* @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall
* @return T
*
* @throws RateLimitException
*/
private function executeRequest(callable $apiCall)
{
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
public function isHubspotRateLimit(Throwable $e): bool
{
if ($e instanceof BadRequest
|| $e instanceof DealApiException
|| $e instanceof ContactApiException
|| $e instanceof CompanyApiException
|| $e instanceof \GuzzleHttp\Exception\RequestException
) {
return (int) $e->getCode() === 429;
}
return false;
}
public function parseRetryAfter(Throwable $e): int
{
// First try to get Retry-After from response headers
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
if (method_exists($e, 'getResponseBody')) {
$body = $e->getResponseBody();
if (is_string($body)) {
$body = json_decode($body, true) ?? [];
}
$policyName = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;
if ($policyName === 'TEN_SECONDLY_ROLLING' || $policyName === 'ten_secondly_rolling') {
return 10;
}
if ($policyName === 'SECONDLY' || $policyName === 'secondly') {
return 1;
}
}
$this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [
'exception_class' => get_class($e),
]);
return 10;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* Execute a search request against HubSpot CRM objects with rate limiting.
*
* @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')
* @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.
* @return array The search response with 'results', 'total', 'paging' keys
* @throws RateLimitException When rate limit is hit
* @throws HubspotException On API errors
*/
public function search(string $objectType, array $payload): array
{
$endpoint = self::BASE_URL . "/crm/v3/objects/{$objectType}/search";
return $this->executeRequest(function () use ($endpoint, $payload) {
$response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);
return $response->toArray();
});
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
);
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
$response = $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
$response = $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
//
// $max = $response->getHeaderLine('X-HubSpot-RateLimit-Max'); // "110"
// $remaining = $response->getHeaderLine('X-HubSpot-RateLimit-Remaining'); // "109"
// $interval = $response->getHeaderLine('X-HubSpot-RateLimit-Interval-Milliseconds'); // "10000"
// $body = json_decode((string) $response->getBody(), true);
//
// \Illuminate\Support\Facades\Log::channel('custom_channel')->info('$max ' . PHP_EOL . print_r($max, true));
// \Illuminate\Support\Facades\Log::channel('custom_channel')->info('$remaining ' . PHP_EOL . print_r($remaining, true));
// \Illuminate\Support\Facades\Log::channel('custom_channel')->info('$interval ' . PHP_EOL . print_r($interval, true));
// \Illuminate\Support\Facades\Log::channel('custom_channel')->info('$body ' . PHP_EOL . print_r($body, true));
return $response;
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
// } catch (RateLimitException $e) {
// throw $e;
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
19
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {
"headers":{
"Date":["Thu,07 May 2026 14:21:15 GMT"],
"Content-Type":["application/json;charset=utf-8"],
"Transfer-Encoding":["chunked"],
"Connection":["keep-alive"],
"CF-Ray":["9f80deb8db60dc3a-SOF"],
"CF-Cache-Status":["DYNAMIC"],
"Strict-Transport-Security":["max-age=31536000; includeSubDomains; preload"],
"Vary":["origin,
accept-encoding"],
"access-control-allow-credentials":["false"],
"server-timing":["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",
cfr;desc=\"9f80deb8e7c6dc3a-IAD\""],
"x-content-type-options":["nosniff"],
"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],
"Set-Cookie":["__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,
07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],
"Report-To":["{
\"endpoints\":[{
\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\"}],
\"group\":\"cf-nel\",
\"max_age\":604800}"],
"NEL":["{
\"success_fraction\":0.01,
\"report_to\":\"cf-nel\",
\"max_age\":604800}"],
"Server":["cloudflare"]}} {
"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab",
"trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20725-handle-HS-search-rate-limit, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.09541223,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20725-handle-HS-search-rate-limit","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8081782,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"bounds":{"left":0.8234708,"top":0.019952115,"width":0.09208777,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2","depth":4,"bounds":{"left":0.35605052,"top":0.17478053,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"65","depth":4,"bounds":{"left":0.36602393,"top":0.17478053,"width":0.010305851,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.37832448,"top":0.17478053,"width":0.00731383,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.38763297,"top":0.17478053,"width":0.00731383,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.39660904,"top":0.17318435,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.4039229,"top":0.17318435,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Reacts to a rate limits (429) from HubSpot by translating it\n * into a RateLimitException carrying retry_after.\n *\n * Wrap any outbound HubSpot call (SDK or raw HTTP) like:\n *\n * $this->executeRequest(fn () => $this->getNewInstance()->crm()->...);\n *\n * @template T\n * @param callable(): T $apiCall\n * @return T\n *\n * @throws RateLimitException\n */\n private function executeRequest(callable $apiCall)\n {\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n public function isHubspotRateLimit(Throwable $e): bool\n {\n if ($e instanceof BadRequest\n || $e instanceof DealApiException\n || $e instanceof ContactApiException\n || $e instanceof CompanyApiException\n || $e instanceof \\GuzzleHttp\\Exception\\RequestException\n ) {\n return (int) $e->getCode() === 429;\n }\n\n return false;\n }\n\n public function parseRetryAfter(Throwable $e): int\n {\n // First try to get Retry-After from response headers\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n if (method_exists($e, 'getResponseBody')) {\n $body = $e->getResponseBody();\n if (is_string($body)) {\n $body = json_decode($body, true) ?? [];\n }\n\n $policyName = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;\n\n if ($policyName === 'TEN_SECONDLY_ROLLING' || $policyName === 'ten_secondly_rolling') {\n return 10;\n }\n if ($policyName === 'SECONDLY' || $policyName === 'secondly') {\n return 1;\n }\n }\n\n $this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [\n 'exception_class' => get_class($e),\n ]);\n\n return 10;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * Execute a search request against HubSpot CRM objects with rate limiting.\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')\n * @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.\n * @return array The search response with 'results', 'total', 'paging' keys\n * @throws RateLimitException When rate limit is hit\n * @throws HubspotException On API errors\n */\n public function search(string $objectType, array $payload): array\n {\n $endpoint = self::BASE_URL . \"/crm/v3/objects/{$objectType}/search\";\n\n return $this->executeRequest(function () use ($endpoint, $payload) {\n $response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);\n\n return $response->toArray();\n });\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n );\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n $response = $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n $response = $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n//\n// $max = $response->getHeaderLine('X-HubSpot-RateLimit-Max'); // \"110\"\n// $remaining = $response->getHeaderLine('X-HubSpot-RateLimit-Remaining'); // \"109\"\n// $interval = $response->getHeaderLine('X-HubSpot-RateLimit-Interval-Milliseconds'); // \"10000\"\n// $body = json_decode((string) $response->getBody(), true);\n//\n// \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$max ' . PHP_EOL . print_r($max, true));\n// \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$remaining ' . PHP_EOL . print_r($remaining, true));\n// \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$interval ' . PHP_EOL . print_r($interval, true));\n// \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$body ' . PHP_EOL . print_r($body, true));\n\n return $response;\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n// } catch (RateLimitException $e) {\n// throw $e;\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Reacts to a rate limits (429) from HubSpot by translating it\n * into a RateLimitException carrying retry_after.\n *\n * Wrap any outbound HubSpot call (SDK or raw HTTP) like:\n *\n * $this->executeRequest(fn () => $this->getNewInstance()->crm()->...);\n *\n * @template T\n * @param callable(): T $apiCall\n * @return T\n *\n * @throws RateLimitException\n */\n private function executeRequest(callable $apiCall)\n {\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n public function isHubspotRateLimit(Throwable $e): bool\n {\n if ($e instanceof BadRequest\n || $e instanceof DealApiException\n || $e instanceof ContactApiException\n || $e instanceof CompanyApiException\n || $e instanceof \\GuzzleHttp\\Exception\\RequestException\n ) {\n return (int) $e->getCode() === 429;\n }\n\n return false;\n }\n\n public function parseRetryAfter(Throwable $e): int\n {\n // First try to get Retry-After from response headers\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n if (method_exists($e, 'getResponseBody')) {\n $body = $e->getResponseBody();\n if (is_string($body)) {\n $body = json_decode($body, true) ?? [];\n }\n\n $policyName = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;\n\n if ($policyName === 'TEN_SECONDLY_ROLLING' || $policyName === 'ten_secondly_rolling') {\n return 10;\n }\n if ($policyName === 'SECONDLY' || $policyName === 'secondly') {\n return 1;\n }\n }\n\n $this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [\n 'exception_class' => get_class($e),\n ]);\n\n return 10;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * Execute a search request against HubSpot CRM objects with rate limiting.\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')\n * @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.\n * @return array The search response with 'results', 'total', 'paging' keys\n * @throws RateLimitException When rate limit is hit\n * @throws HubspotException On API errors\n */\n public function search(string $objectType, array $payload): array\n {\n $endpoint = self::BASE_URL . \"/crm/v3/objects/{$objectType}/search\";\n\n return $this->executeRequest(function () use ($endpoint, $payload) {\n $response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);\n\n return $response->toArray();\n });\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n );\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n $response = $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n $response = $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n//\n// $max = $response->getHeaderLine('X-HubSpot-RateLimit-Max'); // \"110\"\n// $remaining = $response->getHeaderLine('X-HubSpot-RateLimit-Remaining'); // \"109\"\n// $interval = $response->getHeaderLine('X-HubSpot-RateLimit-Interval-Milliseconds'); // \"10000\"\n// $body = json_decode((string) $response->getBody(), true);\n//\n// \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$max ' . PHP_EOL . print_r($max, true));\n// \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$remaining ' . PHP_EOL . print_r($remaining, true));\n// \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$interval ' . PHP_EOL . print_r($interval, true));\n// \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$body ' . PHP_EOL . print_r($body, true));\n\n return $response;\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n// } catch (RateLimitException $e) {\n// throw $e;\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"19","depth":4,"bounds":{"left":0.6296542,"top":0.10055866,"width":0.009640957,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.6409575,"top":0.09896249,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.64827126,"top":0.09896249,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {\n\"headers\":{\n\"Date\":[\"Thu,07 May 2026 14:21:15 GMT\"],\n \"Content-Type\":[\"application/json;charset=utf-8\"],\n \"Transfer-Encoding\":[\"chunked\"],\n \"Connection\":[\"keep-alive\"],\n \"CF-Ray\":[\"9f80deb8db60dc3a-SOF\"],\n \"CF-Cache-Status\":[\"DYNAMIC\"],\n \"Strict-Transport-Security\":[\"max-age=31536000; includeSubDomains; preload\"],\n \"Vary\":[\"origin,\n accept-encoding\"],\n \"access-control-allow-credentials\":[\"false\"],\n \"server-timing\":[\"hcid;desc=\\\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\\\",\n cfr;desc=\\\"9f80deb8e7c6dc3a-IAD\\\"\"],\n \"x-content-type-options\":[\"nosniff\"],\n \"x-hubspot-correlation-id\":[\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\"],\n \"Set-Cookie\":[\"__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-1.0.1.1-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,\n 07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None\"],\n \"Report-To\":[\"{\n\\\"endpoints\\\":[{\n\\\"url\\\":\\\"https:\\\\/\\\\/a.nel.cloudflare.com\\\\/report\\\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\\\"}],\n\\\"group\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"NEL\":[\"{\n\\\"success_fraction\\\":0.01,\n\\\"report_to\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"Server\":[\"cloudflare\"]}} {\n\"correlation_id\":\"95236535-ec98-4541-b92a-adfa73b69eab\",\n\"trace_id\":\"c7ab8365-903f-46d4-9403-0e5b551e3545\"}","depth":4,"bounds":{"left":0.43018618,"top":0.09736632,"width":0.56981385,"height":0.632083},"on_screen":true,"lines":[{"char_start":207,"char_count":30,"bounds":{"left":0.43018618,"top":0.0,"width":0.07513298,"height":0.014365523}},{"char_start":237,"char_count":36,"bounds":{"left":0.43018618,"top":0.0,"width":0.09075798,"height":0.014365523}},{"char_start":273,"char_count":32,"bounds":{"left":0.43018618,"top":0.0,"width":0.080119684,"height":0.014365523}},{"char_start":305,"char_count":79,"bounds":{"left":0.43018618,"top":0.0,"width":0.20212767,"height":0.014365523}},{"char_start":384,"char_count":18,"bounds":{"left":0.43018618,"top":0.0,"width":0.043882977,"height":0.014365523}},{"char_start":402,"char_count":21,"bounds":{"left":0.43018618,"top":0.0,"width":0.051861703,"height":0.014365523}},{"char_start":423,"char_count":48,"bounds":{"left":0.43018618,"top":0.008778931,"width":0.12167553,"height":0.014365523}},{"char_start":471,"char_count":72,"bounds":{"left":0.43018618,"top":0.026336791,"width":0.18384309,"height":0.014365523}},{"char_start":543,"char_count":40,"bounds":{"left":0.43018618,"top":0.043894652,"width":0.10106383,"height":0.014365523}},{"char_start":583,"char_count":41,"bounds":{"left":0.43018618,"top":0.061452515,"width":0.10372341,"height":0.014365523}},{"char_start":624,"char_count":72,"bounds":{"left":0.43018618,"top":0.079010375,"width":0.18384309,"height":0.014365523}},{"char_start":696,"char_count":219,"bounds":{"left":0.43018618,"top":0.096568234,"width":0.56515956,"height":0.014365523}},{"char_start":915,"char_count":83,"bounds":{"left":0.43018618,"top":0.11412609,"width":0.21243352,"height":0.014365523}},{"char_start":998,"char_count":20,"bounds":{"left":0.43018618,"top":0.13168396,"width":0.04920213,"height":0.014365523}},{"char_start":1018,"char_count":17,"bounds":{"left":0.43018618,"top":0.14924182,"width":0.041223403,"height":0.014365523}},{"char_start":1035,"char_count":203,"bounds":{"left":0.43018618,"top":0.16679968,"width":0.52360374,"height":0.014365523}},{"char_start":1238,"char_count":22,"bounds":{"left":0.43018618,"top":0.18435754,"width":0.05418883,"height":0.014365523}},{"char_start":1260,"char_count":23,"bounds":{"left":0.43018618,"top":0.2019154,"width":0.056848403,"height":0.014365523}},{"char_start":1283,"char_count":10,"bounds":{"left":0.43018618,"top":0.21947326,"width":0.023271276,"height":0.014365523}},{"char_start":1293,"char_count":27,"bounds":{"left":0.43018618,"top":0.23703113,"width":0.06715426,"height":0.014365523}},{"char_start":1320,"char_count":26,"bounds":{"left":0.43018618,"top":0.254589,"width":0.06482713,"height":0.014365523}},{"char_start":1346,"char_count":23,"bounds":{"left":0.43018618,"top":0.27214685,"width":0.056848403,"height":0.014365523}},{"char_start":1369,"char_count":28,"bounds":{"left":0.43018618,"top":0.2897047,"width":0.06981383,"height":0.014365523}},{"char_start":1397,"char_count":57,"bounds":{"left":0.43018618,"top":0.30726257,"width":0.14494681,"height":0.014365523}}],"value":"[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {\n\"headers\":{\n\"Date\":[\"Thu,07 May 2026 14:21:15 GMT\"],\n \"Content-Type\":[\"application/json;charset=utf-8\"],\n \"Transfer-Encoding\":[\"chunked\"],\n \"Connection\":[\"keep-alive\"],\n \"CF-Ray\":[\"9f80deb8db60dc3a-SOF\"],\n \"CF-Cache-Status\":[\"DYNAMIC\"],\n \"Strict-Transport-Security\":[\"max-age=31536000; includeSubDomains; preload\"],\n \"Vary\":[\"origin,\n accept-encoding\"],\n \"access-control-allow-credentials\":[\"false\"],\n \"server-timing\":[\"hcid;desc=\\\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\\\",\n cfr;desc=\\\"9f80deb8e7c6dc3a-IAD\\\"\"],\n \"x-content-type-options\":[\"nosniff\"],\n \"x-hubspot-correlation-id\":[\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\"],\n \"Set-Cookie\":[\"__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-1.0.1.1-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,\n 07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None\"],\n \"Report-To\":[\"{\n\\\"endpoints\\\":[{\n\\\"url\\\":\\\"https:\\\\/\\\\/a.nel.cloudflare.com\\\\/report\\\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\\\"}],\n\\\"group\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"NEL\":[\"{\n\\\"success_fraction\\\":0.01,\n\\\"report_to\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"Server\":[\"cloudflare\"]}} {\n\"correlation_id\":\"95236535-ec98-4541-b92a-adfa73b69eab\",\n\"trace_id\":\"c7ab8365-903f-46d4-9403-0e5b551e3545\"}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.011968086,"top":0.047885075,"width":0.024268618,"height":0.024740623},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
8457418728391327329
|
-2844753425483298716
|
visual_change
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
2
65
1
1
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot;
use HubSpot\Client\Crm\Deals\ApiException as DealApiException;
use HubSpot\Client\Crm\Contacts\ApiException as ContactApiException;
use HubSpot\Client\Crm\Companies\ApiException as CompanyApiException;
use HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectWithAssociations as ContactsWithAssociations;
use HubSpot\Client\Crm\Companies\Model\SimplePublicObjectWithAssociations as CompaniesWithAssociations;
use HubSpot\Client\Crm\Deals\Model\SimplePublicObjectWithAssociations as DealWithAssociations;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectInput;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectWithAssociations as ObjectWithAssociations;
use HubSpot\Client\Crm\Pipelines\Model\Error;
use HubSpot\Client\Crm\Pipelines\Model\PipelineStage;
use HubSpot\Client\Crm\Properties\Model\Property;
use HubSpot\Discovery\Discovery;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Crm\Field;
use Jiminny\Services\Crm\BaseClient;
use Jiminny\Services\Crm\Hubspot\DTO\Response\Owner;
use Jiminny\Services\SocialAccountService;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use SevenShores\Hubspot\Factory;
use SevenShores\Hubspot\Http\Response;
use Jiminny\Services\Crm\Hubspot\Pagination\HubspotPaginationService;
use Throwable;
/**
* @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall
* @return T
*
* @throws RateLimitException
*/
private function executeRequest(callable $apiCall)
{
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
public function isHubspotRateLimit(Throwable $e): bool
{
if ($e instanceof BadRequest
|| $e instanceof DealApiException
|| $e instanceof ContactApiException
|| $e instanceof CompanyApiException
|| $e instanceof \GuzzleHttp\Exception\RequestException
) {
return (int) $e->getCode() === 429;
}
return false;
}
public function parseRetryAfter(Throwable $e): int
{
// First try to get Retry-After from response headers
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
if (method_exists($e, 'getResponseBody')) {
$body = $e->getResponseBody();
if (is_string($body)) {
$body = json_decode($body, true) ?? [];
}
$policyName = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;
if ($policyName === 'TEN_SECONDLY_ROLLING' || $policyName === 'ten_secondly_rolling') {
return 10;
}
if ($policyName === 'SECONDLY' || $policyName === 'secondly') {
return 1;
}
}
$this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [
'exception_class' => get_class($e),
]);
return 10;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* Execute a search request against HubSpot CRM objects with rate limiting.
*
* @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')
* @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.
* @return array The search response with 'results', 'total', 'paging' keys
* @throws RateLimitException When rate limit is hit
* @throws HubspotException On API errors
*/
public function search(string $objectType, array $payload): array
{
$endpoint = self::BASE_URL . "/crm/v3/objects/{$objectType}/search";
return $this->executeRequest(function () use ($endpoint, $payload) {
$response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);
return $response->toArray();
});
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
);
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
$response = $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
$response = $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
//
// $max = $response->getHeaderLine('X-HubSpot-RateLimit-Max'); // "110"
// $remaining = $response->getHeaderLine('X-HubSpot-RateLimit-Remaining'); // "109"
// $interval = $response->getHeaderLine('X-HubSpot-RateLimit-Interval-Milliseconds'); // "10000"
// $body = json_decode((string) $response->getBody(), true);
//
// \Illuminate\Support\Facades\Log::channel('custom_channel')->info('$max ' . PHP_EOL . print_r($max, true));
// \Illuminate\Support\Facades\Log::channel('custom_channel')->info('$remaining ' . PHP_EOL . print_r($remaining, true));
// \Illuminate\Support\Facades\Log::channel('custom_channel')->info('$interval ' . PHP_EOL . print_r($interval, true));
// \Illuminate\Support\Facades\Log::channel('custom_channel')->info('$body ' . PHP_EOL . print_r($body, true));
return $response;
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
// } catch (RateLimitException $e) {
// throw $e;
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
19
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {
"headers":{
"Date":["Thu,07 May 2026 14:21:15 GMT"],
"Content-Type":["application/json;charset=utf-8"],
"Transfer-Encoding":["chunked"],
"Connection":["keep-alive"],
"CF-Ray":["9f80deb8db60dc3a-SOF"],
"CF-Cache-Status":["DYNAMIC"],
"Strict-Transport-Security":["max-age=31536000; includeSubDomains; preload"],
"Vary":["origin,
accept-encoding"],
"access-control-allow-credentials":["false"],
"server-timing":["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",
cfr;desc=\"9f80deb8e7c6dc3a-IAD\""],
"x-content-type-options":["nosniff"],
"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],
"Set-Cookie":["__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,
07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],
"Report-To":["{
\"endpoints\":[{
\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\"}],
\"group\":\"cf-nel\",
\"max_age\":604800}"],
"NEL":["{
\"success_fraction\":0.01,
\"report_to\":\"cf-nel\",
\"max_age\":604800}"],
"Server":["cloudflare"]}} {
"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab",
"trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
15771
|
697
|
43
|
2026-05-11T07:13:39.116142+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778483619116_m2.jpg...
|
Notion Calendar
|
NULL
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
NotionMISTOMrTavsco.s?9 JY-20725-handle-HS-search- NotionMISTOMrTavsco.s?9 JY-20725-handle-HS-search-rate-limitProiect© HubspotPaginationService.php>M lustCalli© HubspotSyncStrategyBase.phpm PushSummarvToCrm> D RingCentral>• ZoomPhone© ActivityChangeCatego© AssignOwnership.php(C) ConferenceCrmMatch© MatchactivityermData.php© ermactivilyservice.phgc MatchermData.ono© DeleteActivities.php© DeleteTeamChurnData© DeleteTeamsRetentior© HardDeleteActivities.pc) HarcDeleteacuivity.onc) keindexroraccouniJo!© ReindexForContact.JotC) ReindexForGrouoJob.r© ReindexForLeadJob.pl(C) ReindexForOpportunit© ReindeyForlJser.Job.ph(C) RetrvActivitvSvnc.00.1l@ SyncActivity.php(C) TeardownStream.ohoM Ai AutomationM A Renorts> Audiov AutomatedRenorts(c) ReauectGenerateAck.1© RequestGenerateRepo© SendReportExpiringSo(C) SendPenart loh nhnl© SendReportMailJob.ph© SendReportNotGenera> @ Calendarv D Crmv 0 Delete© DeleteAccountJob.© DeleteContact.Job.r€ DeleteCrmEntityTra© DeleteLeadJob.php© DeleteOpportunityJ© VerifvActivitvCrmTa>MHubspot> M Salesforce© AutoloaDelavedToCrm@ CheckAndRetrvRemoti© CreateFollowupActivit.C) CreateNotes.oho(C) MatchActivitvCrmbate(C) SaveActivitv nhnuse ILluminate Contracts \Queue \ShouLdBeUnique;use "Luminate contracts Queve Shoul doveue:use Illuminate Database Connection;use Illuminate \Queue \InteractsWithQueue;use Illuminate \Queue\SerializesModelsuse iluminate Suoport Facades Loa:use Jiminny Component \Queue \Constants;use Jiminny Excentions InvalidArgumentExcentionsuse Jiminny|Jobs\Job;use Jiminny\Jobs\MiddLeware\HandLeHubspotRateLimit;use Jiminny|Models\Activity;use Jiminny Models\Crm\Configuration;use Jiminny Repositories ActivityRepository:use Jiminny (Services \Crm\CrmActivityService;use Psr \Container\ContainerExceptionInterface;use Psr\Container\NotFoundExceptionInterface;use Throwable:class MatchActivityCrmData extends Job implements ShouldQueue, ShouldBeUniqueuse InteractsWithQueve:use SerializesModels:public int Stries = 3:10 usagesprivate int Sactivitvid:private ?Confiauration sfronConfiauration:orivate hool SremoteSearch.public function middleware: arrayt...}public function construct?int SactivityId,?Configuration $fromConfiguration = null,bool SremoteSearch = false,public function uniqueldo: stringf...}public function timeouto: intf...}1 usagepublic function uniqueForO: intf...}rctand vour Laravel ann code II Generate II Don't Show Anvmore (todav Q•08)© SyncRelatedActivityManager.php© ProspectCache.phpС Cпескапокetrукemotematch.ongMM8AY=custom.log~=laravel.logA SF (# console [PKOb.A console [EU][2026-05-07 14:21:15] local"neaders".?"Date": ["Thu,07 May 2026 14"Transter-Encoding": "chut"CF-Ray":"9t80deb8dbo0dcs"CF-Cache-Status":"DYNAM!"Vary"*"orioin.accent-encodino""server-timino": "hcid:di"Set-Cookip"."" cfhm=.A7-Mav-26 14•51•15 GMT•"Renont-To"."","endpoints\":[{"url\":\"https:|VNV/a.nel\"group)":\"cf-nel\","max_age\":604800}"]|"NEL":["{"cuccess fraction":0.01,"report to\":|"cf-nel\"."max age":604800}"]"Server":["cloudflare"]}} {"correlation_id":"95236535"trace_id":"c7ab8365-903f-4L Lukas Kovalik's No..n HomeEA DSK Report 2023L POS PAYMENT 02.01.2023 13.,Report 2025... MoreFavorites5 YEAR 20262 App replacementRead latenE LOGS1 Report 2024Videos4 Todo* Testã DailyAgents+ New aaentQuick Note- WorkKnowledae• Ideas( Finance hubHome views(A Intearation-appWork Knowledge4 testing keyboard4 Todo2 YEAR 2026( New pagePerconal Home1 LOGS2 Budaet2) Apartmár( Routerª) Population decline explained7 New chat x040 hll"suppon Dally• In 4h 4/ m100% Lz• Mon 11 May 10:13:39<>Hubspot APl callsWork Knowledgeo Hubspot Hubspot APl callsEdited 2d ago*...MethodVia executeRequest(\2Rate Limitclient->getOwnersArchived() →executelANO— RIIPSTapp/services Activity Hubspot/Service.phpThis service uses sthis->cr(the CRM Service.php) - it makes no direct HubSpot API calls itself. All calls delegate through crmService->getCall(.crmService->searchCallsForPeriod(), crmService->syncOpportunity(). crmServiCritical Findings1. Line 1313 — raw searchApi()->doSearch() - matchExactlyByParticipant() in Service.php:cresnonse = Cthic_sclient->aetNewInstance->crmo->contacts->searchAp1→dosearch(Spayloao)• Goes comoletelv around the client wraooer — no 429 handlina, no RateLimitException , no rate limit awareness• Uses the search rate limit bucket• Can be replaced with $this->client->search("contacts', Spayload) - same endpoint, same result, adds 429 protection2. Line 920-923 — companies()->searchByDomain() -matchByDomain():ShsAccounts = Sthis->client->getInstance()->companies()->searchByDomain(ScompanyName, ScompanyProperties):• Usesvi SDK's searchBvDomain which calis a search endooint — hits the search rate limit buckel• No 429 protection• Cannot be trivially replaced with client->search() (different endpoint/format), but could be wrapped in executeRequest(...
|
NULL
|
182849733463417329
|
NULL
|
visual_change
|
ocr
|
NULL
|
NotionMISTOMrTavsco.s?9 JY-20725-handle-HS-search- NotionMISTOMrTavsco.s?9 JY-20725-handle-HS-search-rate-limitProiect© HubspotPaginationService.php>M lustCalli© HubspotSyncStrategyBase.phpm PushSummarvToCrm> D RingCentral>• ZoomPhone© ActivityChangeCatego© AssignOwnership.php(C) ConferenceCrmMatch© MatchactivityermData.php© ermactivilyservice.phgc MatchermData.ono© DeleteActivities.php© DeleteTeamChurnData© DeleteTeamsRetentior© HardDeleteActivities.pc) HarcDeleteacuivity.onc) keindexroraccouniJo!© ReindexForContact.JotC) ReindexForGrouoJob.r© ReindexForLeadJob.pl(C) ReindexForOpportunit© ReindeyForlJser.Job.ph(C) RetrvActivitvSvnc.00.1l@ SyncActivity.php(C) TeardownStream.ohoM Ai AutomationM A Renorts> Audiov AutomatedRenorts(c) ReauectGenerateAck.1© RequestGenerateRepo© SendReportExpiringSo(C) SendPenart loh nhnl© SendReportMailJob.ph© SendReportNotGenera> @ Calendarv D Crmv 0 Delete© DeleteAccountJob.© DeleteContact.Job.r€ DeleteCrmEntityTra© DeleteLeadJob.php© DeleteOpportunityJ© VerifvActivitvCrmTa>MHubspot> M Salesforce© AutoloaDelavedToCrm@ CheckAndRetrvRemoti© CreateFollowupActivit.C) CreateNotes.oho(C) MatchActivitvCrmbate(C) SaveActivitv nhnuse ILluminate Contracts \Queue \ShouLdBeUnique;use "Luminate contracts Queve Shoul doveue:use Illuminate Database Connection;use Illuminate \Queue \InteractsWithQueue;use Illuminate \Queue\SerializesModelsuse iluminate Suoport Facades Loa:use Jiminny Component \Queue \Constants;use Jiminny Excentions InvalidArgumentExcentionsuse Jiminny|Jobs\Job;use Jiminny\Jobs\MiddLeware\HandLeHubspotRateLimit;use Jiminny|Models\Activity;use Jiminny Models\Crm\Configuration;use Jiminny Repositories ActivityRepository:use Jiminny (Services \Crm\CrmActivityService;use Psr \Container\ContainerExceptionInterface;use Psr\Container\NotFoundExceptionInterface;use Throwable:class MatchActivityCrmData extends Job implements ShouldQueue, ShouldBeUniqueuse InteractsWithQueve:use SerializesModels:public int Stries = 3:10 usagesprivate int Sactivitvid:private ?Confiauration sfronConfiauration:orivate hool SremoteSearch.public function middleware: arrayt...}public function construct?int SactivityId,?Configuration $fromConfiguration = null,bool SremoteSearch = false,public function uniqueldo: stringf...}public function timeouto: intf...}1 usagepublic function uniqueForO: intf...}rctand vour Laravel ann code II Generate II Don't Show Anvmore (todav Q•08)© SyncRelatedActivityManager.php© ProspectCache.phpС Cпескапокetrукemotematch.ongMM8AY=custom.log~=laravel.logA SF (# console [PKOb.A console [EU][2026-05-07 14:21:15] local"neaders".?"Date": ["Thu,07 May 2026 14"Transter-Encoding": "chut"CF-Ray":"9t80deb8dbo0dcs"CF-Cache-Status":"DYNAM!"Vary"*"orioin.accent-encodino""server-timino": "hcid:di"Set-Cookip"."" cfhm=.A7-Mav-26 14•51•15 GMT•"Renont-To"."","endpoints\":[{"url\":\"https:|VNV/a.nel\"group)":\"cf-nel\","max_age\":604800}"]|"NEL":["{"cuccess fraction":0.01,"report to\":|"cf-nel\"."max age":604800}"]"Server":["cloudflare"]}} {"correlation_id":"95236535"trace_id":"c7ab8365-903f-4L Lukas Kovalik's No..n HomeEA DSK Report 2023L POS PAYMENT 02.01.2023 13.,Report 2025... MoreFavorites5 YEAR 20262 App replacementRead latenE LOGS1 Report 2024Videos4 Todo* Testã DailyAgents+ New aaentQuick Note- WorkKnowledae• Ideas( Finance hubHome views(A Intearation-appWork Knowledge4 testing keyboard4 Todo2 YEAR 2026( New pagePerconal Home1 LOGS2 Budaet2) Apartmár( Routerª) Population decline explained7 New chat x040 hll"suppon Dally• In 4h 4/ m100% Lz• Mon 11 May 10:13:39<>Hubspot APl callsWork Knowledgeo Hubspot Hubspot APl callsEdited 2d ago*...MethodVia executeRequest(\2Rate Limitclient->getOwnersArchived() →executelANO— RIIPSTapp/services Activity Hubspot/Service.phpThis service uses sthis->cr(the CRM Service.php) - it makes no direct HubSpot API calls itself. All calls delegate through crmService->getCall(.crmService->searchCallsForPeriod(), crmService->syncOpportunity(). crmServiCritical Findings1. Line 1313 — raw searchApi()->doSearch() - matchExactlyByParticipant() in Service.php:cresnonse = Cthic_sclient->aetNewInstance->crmo->contacts->searchAp1→dosearch(Spayloao)• Goes comoletelv around the client wraooer — no 429 handlina, no RateLimitException , no rate limit awareness• Uses the search rate limit bucket• Can be replaced with $this->client->search("contacts', Spayload) - same endpoint, same result, adds 429 protection2. Line 920-923 — companies()->searchByDomain() -matchByDomain():ShsAccounts = Sthis->client->getInstance()->companies()->searchByDomain(ScompanyName, ScompanyProperties):• Usesvi SDK's searchBvDomain which calis a search endooint — hits the search rate limit buckel• No 429 protection• Cannot be trivially replaced with client->search() (different endpoint/format), but could be wrapped in executeRequest(...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
16737
|
746
|
43
|
2026-05-11T09:19:56.608967+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778491196608_m1.jpg...
|
PhpStorm
|
faVsco.js – PlaybackController.php
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20725-handle-HS-search-rate-limit, menu","depth":5,"on_screen":true,"help_text":"Git Branch: JY-20725-handle-HS-search-rate-limit","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
5988960105550556897
|
-8204420481362449466
|
click
|
hybrid
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
SlackFileEditViewGolHistoryWindowHelp6д Huddle with Petko KashinskiPetko KashinskiScreen shareChromeFileEditViewHistoryBookmarksProfilesTabWindowHelpWorkGreelScoreandrewilsoCall AJiminM Inbox=N→ws.planhat.com/jiminny/home/data-explorer/usagemetricdef?preview=UsageMetricDef.67489a8c40ddfa05d5bf5aa4D АIKВChatPlayground Al...D AppsJiminny ~CalendarData ExplorerEmail ManagerMoreoooasCS Day-to-day -Getting started Guide• Just CS DataDaily OperationsWeekly prepRenewals and UpsellRisk and Churn AnalyticsImplementation -Impl ProjectsTrial Opps (Under Review)Stoyan's clientsLeadership •System ReportsLeadership OperationsPordollo Overview lbasnoo.NPS KOpON- OTeyClient Engagement OverviewRevenue Analytics10 Jiminny - Calenda...M GMail• My Calendly - Eve...= PH New UI LoginGet Starting with J...Search Jiminny8 Metric -EB DatasetPlayback AdoptionQ PLAYBACK+ MetricReporting & Data modeis (Featured)calculated.67489a8c40ddfaO5dSbf5aa4NameTytOverviewLogsTraceCompany 2• May 11, 2026• Playback Adoption AvgCal02:02 - Metric rebuild queued, executed by system user• Playback AdoptionCal• May 10, 202602:01 - Metric rebuild queued, executed by system userv EndUser 4• May 09, 2026• JUsers Playback AdoptionCal06-26 - Metric rebuiid success, executed by system user• Playback Adoption (Last 7 days)Cal• May 08, 2026• Playback Adoption05:17 - Metric rebulld success, executed by system userplaybackVisited• May 07, 202605:16 - Metric rebuild success, executed by system user• May 06, 202607-27 - Metric rebuild success, executed by system user• May 05, 202605:04 - Metric rebuild success, executed by system userSupport Daily - in 2h 41 m100% <28• Mon 11 May 12:19:56QAppsBuildu Users€ New• Chloe Onboarding....+ CX Journey SMB.....+8•Mon 11 May 12:19User+Work+E PetkoAl Notes: OffE88&Logs History is limited to 90 days in your current Plan. Upgrade for200m7Petko ..reen.ГА2:25Leave...
|
16734
|
NULL
|
NULL
|
NULL
|
|
17279
|
769
|
43
|
2026-05-11T10:15:36.086246+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778494536086_m2.jpg...
|
Notion Calendar
|
NULL
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
rostmanFavouritesjiminny(* AirDrop• RecentsA Appli rostmanFavouritesjiminny(* AirDrop• RecentsA Applications9 Documents• Downloadsii lukasIcloud• iCloud Drive992 Svnc toldeLocations0 DXP4800PLUS-B5F A49 Network• CRM• Orange|• Red• Yellow• Greer• Blue• Purple• All lags..caltVIewWindowmelparchive.db• #recycledb.sqlite-shmdb.sqlitevi loassync.log• screenpipe.2026-05-07.0.1ogv data•2026-05-072026-05-062026-04.292026-04-27> 2026-04-25•2026-04-24> 2026-04-22• 2026-04-232026-04-20• 2026.04.212026-04-172026-04-16• 2026-04-15• 2026-04-14screenpipe_sync_updated.sharchive. db-oak>?app• db.sqlite-walscreenpipe_sync.shann cettinas ison• screenpipe.db›_pipeshel"suppont Dally • In Th 40m100% 2• Mon 11 May 13:15:35X& HubspotYour team is now on the Free plan with 1 admin. You retain editing access and other members are read-only. View team permissions to see who can edit, or upgrade to restore collaborationCOLLECTIONSGET get meetingPost get link to task• Hubspot• Iteration run HSge. An error occurred.cg. successful operation• Iteration run Search HS• ©Authi• Properties, SFARCHIPOST search contact by emaiPoSt Sparch related meetinas v3Tickets• Get get history of property - deal stageGET aet ucereGET SF oauth> GET Meeting outcomes per meetingGEt Read all pronerties oldlcet old call dispositionsGET list engagements oldSustem Resource WarningНIP Useful › Get Engagement (v1)= DocsRearer TokenBO0Vcf-rayct-cache-statusSustem resources are constrained. Thesystem may not be able to generate the loadeded for this test and the cest is likely toSAIl*) SaveCKel8LThMxIZOINOMI8kOEwr.Save changes?Get Enaagement (v1) has unsaved changes. Save these chandes toavoid losing vour work.• Always discard unsaved changes when closing a tab ®Don't savealelunaeealia• 1// ms • 1.23 KB • UAIe.g. save kesponsefalcelnosniff010002d2.6010.7275-9690-6A10f650291210000109("success fraction":0.01"report_to":"cf-nel""max age":604800}Globals Vault Tools? 0 0 0...
|
NULL
|
298981581088797586
|
NULL
|
click
|
ocr
|
NULL
|
rostmanFavouritesjiminny(* AirDrop• RecentsA Appli rostmanFavouritesjiminny(* AirDrop• RecentsA Applications9 Documents• Downloadsii lukasIcloud• iCloud Drive992 Svnc toldeLocations0 DXP4800PLUS-B5F A49 Network• CRM• Orange|• Red• Yellow• Greer• Blue• Purple• All lags..caltVIewWindowmelparchive.db• #recycledb.sqlite-shmdb.sqlitevi loassync.log• screenpipe.2026-05-07.0.1ogv data•2026-05-072026-05-062026-04.292026-04-27> 2026-04-25•2026-04-24> 2026-04-22• 2026-04-232026-04-20• 2026.04.212026-04-172026-04-16• 2026-04-15• 2026-04-14screenpipe_sync_updated.sharchive. db-oak>?app• db.sqlite-walscreenpipe_sync.shann cettinas ison• screenpipe.db›_pipeshel"suppont Dally • In Th 40m100% 2• Mon 11 May 13:15:35X& HubspotYour team is now on the Free plan with 1 admin. You retain editing access and other members are read-only. View team permissions to see who can edit, or upgrade to restore collaborationCOLLECTIONSGET get meetingPost get link to task• Hubspot• Iteration run HSge. An error occurred.cg. successful operation• Iteration run Search HS• ©Authi• Properties, SFARCHIPOST search contact by emaiPoSt Sparch related meetinas v3Tickets• Get get history of property - deal stageGET aet ucereGET SF oauth> GET Meeting outcomes per meetingGEt Read all pronerties oldlcet old call dispositionsGET list engagements oldSustem Resource WarningНIP Useful › Get Engagement (v1)= DocsRearer TokenBO0Vcf-rayct-cache-statusSustem resources are constrained. Thesystem may not be able to generate the loadeded for this test and the cest is likely toSAIl*) SaveCKel8LThMxIZOINOMI8kOEwr.Save changes?Get Enaagement (v1) has unsaved changes. Save these chandes toavoid losing vour work.• Always discard unsaved changes when closing a tab ®Don't savealelunaeealia• 1// ms • 1.23 KB • UAIe.g. save kesponsefalcelnosniff010002d2.6010.7275-9690-6A10f650291210000109("success fraction":0.01"report_to":"cf-nel""max age":604800}Globals Vault Tools? 0 0 0...
|
17277
|
NULL
|
NULL
|
NULL
|
|
17289
|
768
|
43
|
2026-05-11T10:15:50.515478+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778494550515_m1.jpg...
|
Notion Calendar
|
NULL
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
iTerm2•ShellEditViewSessionScriptsProfilesWindowHe iTerm2•ShellEditViewSessionScriptsProfilesWindowHelplih§ Support Daily • in 1h 45 mDOCKER881DEV (docker)H82APP (-zsh)DEV (docker)X3-zshl84-zsh100%8• Mon 11 May 13:15:50181screenpipe"0 ₴6configcachecompiledeventsroutesviewsjiminny-worker-processing-2:jiminny-worker-processing-2_00: stoppedjiminny-worker-processing-3:jiminny-worker-processing-3_00:stoppedjiminny-worker-processing-4:jiminny-worker-processing-4_00:stoppedjiminny-worker-processing-5:jiminny-worker-processing-5_00:stoppedjiminny-worker-processing-delayed: jiminny-worker-processing-delayed_00: stoppedworker-analytics:worker-analytics_00: stoppedworker-conferences:worker-conferences_00: stoppedworker-crm-update:worker-crm-update_00: stoppedworker-download:worker-download_00: stoppedworker-emails:worker-emails_00: stoppedworker-nudges:worker-nudges_00: stoppedworker:worker_00: stoppedworker-audio:worker-audio_00: stoppedworker-calendar:worker-calendar_00: stoppedworker-crm-sync:worker-crm-sync_00: stoppedartisan-schedule:artisan-schedule_00: stoppedworker-es-update:worker-es-update_00: stoppedjiminny-worker-processing-1:jiminny-worker-processing-1_00: stoppedartisan-schedule:artisan-schedule_00: startedjiminny-worker-processing-1:jiminny-worker-processing-1_00: startedjiminny-worker-processing-2:jiminny-worker-processing-2_00: startedjiminny-worker-processing-3:jiminny-worker-processing-3_00: startedjiminny-worker-processing-4:jiminny-worker-processing-4_00: startedjiminny-worker-processing-5:jiminny-worker-processing-5_00: startedjiminny-worker-processing-delayed:jiminny-worker-processing-delayed_00:startedworker:worker_00: startedworker-analytics:worker-analytics_00: startedworker-audio:worker-audio_00: startedworker-calendar:worker-calendar_00: startedworker-conferences:worker-conferences_00: startedworker-crm-sync:worker-crm-sync_00: startedworker-crm-update:worker-crm-update_00: startedworker-download:worker-download_00:startedworker-emails:worker-emails_00: startedworker-es-update:worker-es-update_00: startedworker-nudges:worker-nudges_00:startedroot@docker_lamp_1:/home/jiminny#php artisan jiminny: debugll88510.53ms DONE128.25ms DONE1.73ms DONE1.07ms DONE1.45ms DONE5.46ms DONEDEV...
|
NULL
|
6486733889848914980
|
NULL
|
click
|
ocr
|
NULL
|
iTerm2•ShellEditViewSessionScriptsProfilesWindowHe iTerm2•ShellEditViewSessionScriptsProfilesWindowHelplih§ Support Daily • in 1h 45 mDOCKER881DEV (docker)H82APP (-zsh)DEV (docker)X3-zshl84-zsh100%8• Mon 11 May 13:15:50181screenpipe"0 ₴6configcachecompiledeventsroutesviewsjiminny-worker-processing-2:jiminny-worker-processing-2_00: stoppedjiminny-worker-processing-3:jiminny-worker-processing-3_00:stoppedjiminny-worker-processing-4:jiminny-worker-processing-4_00:stoppedjiminny-worker-processing-5:jiminny-worker-processing-5_00:stoppedjiminny-worker-processing-delayed: jiminny-worker-processing-delayed_00: stoppedworker-analytics:worker-analytics_00: stoppedworker-conferences:worker-conferences_00: stoppedworker-crm-update:worker-crm-update_00: stoppedworker-download:worker-download_00: stoppedworker-emails:worker-emails_00: stoppedworker-nudges:worker-nudges_00: stoppedworker:worker_00: stoppedworker-audio:worker-audio_00: stoppedworker-calendar:worker-calendar_00: stoppedworker-crm-sync:worker-crm-sync_00: stoppedartisan-schedule:artisan-schedule_00: stoppedworker-es-update:worker-es-update_00: stoppedjiminny-worker-processing-1:jiminny-worker-processing-1_00: stoppedartisan-schedule:artisan-schedule_00: startedjiminny-worker-processing-1:jiminny-worker-processing-1_00: startedjiminny-worker-processing-2:jiminny-worker-processing-2_00: startedjiminny-worker-processing-3:jiminny-worker-processing-3_00: startedjiminny-worker-processing-4:jiminny-worker-processing-4_00: startedjiminny-worker-processing-5:jiminny-worker-processing-5_00: startedjiminny-worker-processing-delayed:jiminny-worker-processing-delayed_00:startedworker:worker_00: startedworker-analytics:worker-analytics_00: startedworker-audio:worker-audio_00: startedworker-calendar:worker-calendar_00: startedworker-conferences:worker-conferences_00: startedworker-crm-sync:worker-crm-sync_00: startedworker-crm-update:worker-crm-update_00: startedworker-download:worker-download_00:startedworker-emails:worker-emails_00: startedworker-es-update:worker-es-update_00: startedworker-nudges:worker-nudges_00:startedroot@docker_lamp_1:/home/jiminny#php artisan jiminny: debugll88510.53ms DONE128.25ms DONE1.73ms DONE1.07ms DONE1.45ms DONE5.46ms DONEDEV...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
17398
|
771
|
43
|
2026-05-11T10:21:37.073983+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778494897073_m2.jpg...
|
PhpStorm
|
faVsco.js – Client.php
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
2
68
3
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot;
use HubSpot\Client\Crm\Deals\ApiException as DealApiException;
use HubSpot\Client\Crm\Contacts\ApiException as ContactApiException;
use HubSpot\Client\Crm\Companies\ApiException as CompanyApiException;
use HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectWithAssociations as ContactsWithAssociations;
use HubSpot\Client\Crm\Companies\Model\SimplePublicObjectWithAssociations as CompaniesWithAssociations;
use HubSpot\Client\Crm\Deals\Model\SimplePublicObjectWithAssociations as DealWithAssociations;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectInput;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectWithAssociations as ObjectWithAssociations;
use HubSpot\Client\Crm\Pipelines\Model\Error;
use HubSpot\Client\Crm\Pipelines\Model\PipelineStage;
use HubSpot\Client\Crm\Properties\Model\Property;
use HubSpot\Discovery\Discovery;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Crm\Field;
use Jiminny\Services\Crm\BaseClient;
use Jiminny\Services\Crm\Hubspot\DTO\Response\Owner;
use Jiminny\Services\SocialAccountService;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use SevenShores\Hubspot\Factory;
use SevenShores\Hubspot\Http\Response;
use Jiminny\Services\Crm\Hubspot\Pagination\HubspotPaginationService;
use Illuminate\Support\Facades\Redis;
use Throwable;
/**
* @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall
* @return T
*
* @throws RateLimitException
*/
private function executeRequest(callable $apiCall)
{
$cacheKey = $this->getRateLimitCacheKey();
$cachedRetryAfter = Redis::get($cacheKey);
if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {
throw new RateLimitException(
'Hubspot rate limit (cached circuit-breaker)',
(int) $cachedRetryAfter,
);
}
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'policy' => $this->parsePolicy($e),
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
private function getRateLimitCacheKey(): string
{
return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());
}
public function isHubspotRateLimit(Throwable $e): bool
{
if ($e instanceof BadRequest
|| $e instanceof DealApiException
|| $e instanceof ContactApiException
|| $e instanceof CompanyApiException
|| $e instanceof \GuzzleHttp\Exception\RequestException
) {
return (int) $e->getCode() === 429;
}
return false;
}
public function parseRetryAfter(Throwable $e): int
{
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
$policy = $this->parsePolicy($e);
if ($policy === 'TEN_SECONDLY_ROLLING') {
return 10;
}
if ($policy === 'SECONDLY') {
return 1;
}
if ($policy === 'DAILY_LIMIT') {
return 600;
}
$this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [
'exception_class' => get_class($e),
]);
return 10;
}
public function parsePolicy(Throwable $e): ?string
{
if (! method_exists($e, 'getResponseBody')) {
return null;
}
$body = $e->getResponseBody();
if (is_string($body)) {
$body = json_decode($body, true) ?? [];
}
if (! is_array($body)) {
return null;
}
$policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;
return is_string($policy) ? strtoupper($policy) : null;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* Execute a search request against HubSpot CRM objects with rate limiting.
*
* @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')
* @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.
* @return array The search response with 'results', 'total', 'paging' keys
* @throws RateLimitException When rate limit is hit
* @throws HubspotException On API errors
*/
public function search(string $objectType, array $payload): array
{
$endpoint = self::BASE_URL . "/crm/v3/objects/{$objectType}/search";
return $this->executeRequest(function () use ($endpoint, $payload) {
$response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);
return $response->toArray();
});
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
);
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
return $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
return $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
// } catch (RateLimitException $e) {
// throw $e;
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
Show Replace Field
Search History
Received 429 from API
New Line
Match Case
Words
Regex
Replace History
Replace
New Line
Preserve case
1/5
Previous Occurrence
Next Occurrence
Filter Search Results
Open in Window, Multiple Cursors
Click to highlight
Close
Sync Changes
Hide This Notification
Code changed:
Hide
523
Previous Highlighted Error
Next Highlighted Error
[2026-05-11 10:17:03] local.INFO: [MatchActivityCrmData] Starting CRM data matching {"activity":615092,"remote_search":true,"set_configuration":2,"old_state":{"lead_id":null,"contact_id":null,"account_id":26,"opportunity_id":22,"stage_id":89}} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:03] local.INFO: [ EsUpdateTarget ] Update single target {"target":"activities","purpose":"searchable-observer-update","entityId":615092} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:03] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {"entityType":"activities","entityId":615092,"collectionKey":"activities-for-update-priority","withPriority":true} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:03] local.INFO: [MatchActivityCrmData] Participants old state {"activity":615092,"participants":[{"id":1004102,"user_id":null,"contact_id":null,"lead_id":null},{"id":1004103,"user_id":89,"contact_id":null,"lead_id":null}]} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:03] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:03] local.INFO: [SocialAccountService] Token retrieved {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:03] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:03] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {"crm_provider":"hubspot","crm_owner":148,"team_id":2} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:03] local.INFO: [Prospect match] Cache miss, calling the API {"identifier_type":"email","identifier":"[EMAIL]"} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:03] local.INFO: [Hubspot] Failed to fetch contact {"email":"[EMAIL]","reason":"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/nikolay.nikolov%40jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response"} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:03] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {"identifier_type":"email","identifier":"[EMAIL]"} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.WARNING: [Hubspot] No retry-after header or policy name found, using default {"exception_class":"SevenShores\\Hubspot\\Exceptions\\BadRequest"} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.WARNING: [Hubspot] Received 429 from API {"team_id":2,"config_id":2,"retry_after":10,"policy":null,"reason":"Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response:
{\"status\":\"error\",\"message\":\"You have reached your secondly limit.\",\"errorType\":\"RATE_LIMIT\",\"correlationId\":\"019e168a-5 (truncated...)
"} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {"job_class":"Jiminny\\Jobs\\Crm\\MatchActivityCrmData","attempts":1,"retry_after":10,"delay":14} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {"activity":614436,"remote_search":true,"set_configuration":2,"old_state":{"lead_id":null,"contact_id":null,"account_id":26,"opportunity_id":22,"stage_id":89}} {"correlation_id":"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {"target":"activities","purpose":"searchable-observer-update","entityId":614436} {"correlation_id":"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {"entityType":"activities","entityId":614436,"collectionKey":"activities-for-update-priority","withPriority":true} {"correlation_id":"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {"activity":614436,"participants":[{"id":1002751,"user_id":null,"contact_id":null,"lead_id":null},{"id":1002752,"user_id":89,"contact_id":null,"lead_id":null}]} {"correlation_id":"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {"crm_provider":"hubspot","crm_owner":148,"team_id":2} {"correlation_id":"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {"identifier_type":"email","identifier":"[EMAIL]"} {"correlation_id":"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {"identifier_type":"email","identifier":"[EMAIL]"} {"correlation_id":"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {"job_class":"Jiminny\\Jobs\\Crm\\MatchActivityCrmData","attempts":1,"retry_after":10,"delay":14} {"correlation_id":"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {"activity":614382,"remote_search":true,"set_configuration":2,"old_state":{"lead_id":null,"contact_id":null,"account_id":26,"opportunity_id":22,"stage_id":89}} {"correlation_id":"78f847cf-6495-4054-b3d4-e179a133bd42","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {"target":"activities","purpose":"searchable-observer-update","entityId":614382} {"correlation_id":"78f847cf-6495-4054-b3d4-e179a133bd42","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {"entityType":"activities","entityId":614382,"collectionKey":"activities-for-update-priority","withPriority":true} {"correlation_id":"78f847cf-6495-4054-b3d4-e179a133bd42","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {"activity":614382,"participants":[{"id":1002632,"user_id":null,"contact_id":null,"lead_id":null},{"id":1002633,"user_id":89,"contact_id":null,"lead_id":null}]} {"correlation_id":"78f847cf-6495-4054-b3d4-e179a133bd42","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"78f847cf-6495-4054-b3d4-e179a133bd42","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"78f847cf-6495-4054-b3d4-e179a133bd42","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"78f847cf-6495-4054-b3d4-e179a133bd42","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {"crm_provider":"hubspot","crm_owner":148,"team_id":2} {"correlation_id":"78f847cf-6495-4054-b3d4-e179a133bd42","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {"identifier_type":"email","identifier":"[EMAIL]"} {"correlation_id":"78f847cf-6495-4054-b3d4-e179a133bd42","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {"identifier_type":"email","identifier":"[EMAIL]"} {"correlation_id":"78f847cf-6495-4054-b3d4-e179a133bd42","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {"job_class":"Jiminny\\Jobs\\Crm\\MatchActivityCrmData","attempts":1,"retry_after":10,"delay":11} {"correlation_id":"78f847cf-6495-4054-b3d4-e179a133bd42","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {"activity":614381,"remote_search":true,"set_configuration":2,"old_state":{"lead_id":null,"contact_id":null,"account_id":26,"opportunity_id":22,"stage_id":89}} {"correlation_id":"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {"target":"activities","purpose":"searchable-observer-update","entityId":614381} {"correlation_id":"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {"entityType":"activities","entityId":614381,"collectionKey":"activities-for-update-priority","withPriority":true} {"correlation_id":"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {"activity":614381,"participants":[{"id":1002630,"user_id":null,"contact_id":null,"lead_id":null},{"id":1002631,"user_id":89,"contact_id":null,"lead_id":null}]} {"correlation_id":"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {"crm_provider":"hubspot","crm_owner":148,"team_id":2} {"correlation_id":"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {"identifier_type":"email","identifier":"[EMAIL]"} {"correlation_id":"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {"identifier_type":"email","identifier":"[EMAIL]"} {"correlation_id":"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {"job_class":"Jiminny\\Jobs\\Crm\\MatchActivityCrmData","attempts":1,"retry_after":10,"delay":11} {"correlation_id":"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {"activity":614378,"remote_search":true,"set_configuration":2,"old_state":{"lead_id":null,"contact_id":6167,"account_id":null,"opportunity_id":null,"stage_id":null}} {"correlation_id":"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {"target":"activities","purpose":"searchable-observer-update","entityId":614378} {"correlation_id":"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {"entityType":"activities","entityId":614378,"collectionKey":"activities-for-update-priority","withPriority":true} {"correlation_id":"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {"activity":614378,"participants":[{"id":1002623,"user_id":null,"contact_id":null,"lead_id":null},{"id":1002624,"user_id":null,"contact_id":6167,"lead_id":null},{"id":1002625,"user_id":89,"contact_id":null,"lead_id":null}]} {"correlation_id":"2522b1c9-...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20725-handle-HS-search-rate-limit, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.09541223,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20725-handle-HS-search-rate-limit","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.82413566,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"HandleHubspotRateLimitTest","depth":6,"bounds":{"left":0.8394282,"top":0.019952115,"width":0.076130316,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'HandleHubspotRateLimitTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'HandleHubspotRateLimitTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2","depth":4,"bounds":{"left":0.5515292,"top":0.17478053,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"68","depth":4,"bounds":{"left":0.56150264,"top":0.17478053,"width":0.010305851,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"3","depth":4,"bounds":{"left":0.5738032,"top":0.17478053,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.5834442,"top":0.17318435,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.59075797,"top":0.17318435,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Illuminate\\Support\\Facades\\Redis;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Reacts to a rate limits (429) from HubSpot by translating it\n * into a RateLimitException carrying retry_after.\n *\n * Wrap any outbound HubSpot call (SDK or raw HTTP) like:\n *\n * $this->executeRequest(fn () => $this->getNewInstance()->crm()->...);\n *\n * @template T\n * @param callable(): T $apiCall\n * @return T\n *\n * @throws RateLimitException\n */\n private function executeRequest(callable $apiCall)\n {\n $cacheKey = $this->getRateLimitCacheKey();\n\n $cachedRetryAfter = Redis::get($cacheKey);\n if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {\n throw new RateLimitException(\n 'Hubspot rate limit (cached circuit-breaker)',\n (int) $cachedRetryAfter,\n );\n }\n\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'policy' => $this->parsePolicy($e),\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n private function getRateLimitCacheKey(): string\n {\n return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());\n }\n\n public function isHubspotRateLimit(Throwable $e): bool\n {\n if ($e instanceof BadRequest\n || $e instanceof DealApiException\n || $e instanceof ContactApiException\n || $e instanceof CompanyApiException\n || $e instanceof \\GuzzleHttp\\Exception\\RequestException\n ) {\n return (int) $e->getCode() === 429;\n }\n\n return false;\n }\n\n public function parseRetryAfter(Throwable $e): int\n {\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n $policy = $this->parsePolicy($e);\n if ($policy === 'TEN_SECONDLY_ROLLING') {\n return 10;\n }\n if ($policy === 'SECONDLY') {\n return 1;\n }\n if ($policy === 'DAILY_LIMIT') {\n return 600;\n }\n\n $this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [\n 'exception_class' => get_class($e),\n ]);\n\n return 10;\n }\n\n public function parsePolicy(Throwable $e): ?string\n {\n if (! method_exists($e, 'getResponseBody')) {\n return null;\n }\n\n $body = $e->getResponseBody();\n if (is_string($body)) {\n $body = json_decode($body, true) ?? [];\n }\n\n if (! is_array($body)) {\n return null;\n }\n\n $policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;\n\n return is_string($policy) ? strtoupper($policy) : null;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * Execute a search request against HubSpot CRM objects with rate limiting.\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')\n * @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.\n * @return array The search response with 'results', 'total', 'paging' keys\n * @throws RateLimitException When rate limit is hit\n * @throws HubspotException On API errors\n */\n public function search(string $objectType, array $payload): array\n {\n $endpoint = self::BASE_URL . \"/crm/v3/objects/{$objectType}/search\";\n\n return $this->executeRequest(function () use ($endpoint, $payload) {\n $response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);\n\n return $response->toArray();\n });\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n );\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n return $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n return $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n// } catch (RateLimitException $e) {\n// throw $e;\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Illuminate\\Support\\Facades\\Redis;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Reacts to a rate limits (429) from HubSpot by translating it\n * into a RateLimitException carrying retry_after.\n *\n * Wrap any outbound HubSpot call (SDK or raw HTTP) like:\n *\n * $this->executeRequest(fn () => $this->getNewInstance()->crm()->...);\n *\n * @template T\n * @param callable(): T $apiCall\n * @return T\n *\n * @throws RateLimitException\n */\n private function executeRequest(callable $apiCall)\n {\n $cacheKey = $this->getRateLimitCacheKey();\n\n $cachedRetryAfter = Redis::get($cacheKey);\n if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {\n throw new RateLimitException(\n 'Hubspot rate limit (cached circuit-breaker)',\n (int) $cachedRetryAfter,\n );\n }\n\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'policy' => $this->parsePolicy($e),\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n private function getRateLimitCacheKey(): string\n {\n return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());\n }\n\n public function isHubspotRateLimit(Throwable $e): bool\n {\n if ($e instanceof BadRequest\n || $e instanceof DealApiException\n || $e instanceof ContactApiException\n || $e instanceof CompanyApiException\n || $e instanceof \\GuzzleHttp\\Exception\\RequestException\n ) {\n return (int) $e->getCode() === 429;\n }\n\n return false;\n }\n\n public function parseRetryAfter(Throwable $e): int\n {\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n $policy = $this->parsePolicy($e);\n if ($policy === 'TEN_SECONDLY_ROLLING') {\n return 10;\n }\n if ($policy === 'SECONDLY') {\n return 1;\n }\n if ($policy === 'DAILY_LIMIT') {\n return 600;\n }\n\n $this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [\n 'exception_class' => get_class($e),\n ]);\n\n return 10;\n }\n\n public function parsePolicy(Throwable $e): ?string\n {\n if (! method_exists($e, 'getResponseBody')) {\n return null;\n }\n\n $body = $e->getResponseBody();\n if (is_string($body)) {\n $body = json_decode($body, true) ?? [];\n }\n\n if (! is_array($body)) {\n return null;\n }\n\n $policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;\n\n return is_string($policy) ? strtoupper($policy) : null;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * Execute a search request against HubSpot CRM objects with rate limiting.\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')\n * @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.\n * @return array The search response with 'results', 'total', 'paging' keys\n * @throws RateLimitException When rate limit is hit\n * @throws HubspotException On API errors\n */\n public function search(string $objectType, array $payload): array\n {\n $endpoint = self::BASE_URL . \"/crm/v3/objects/{$objectType}/search\";\n\n return $this->executeRequest(function () use ($endpoint, $payload) {\n $response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);\n\n return $response->toArray();\n });\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n );\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n return $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n return $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n// } catch (RateLimitException $e) {\n// throw $e;\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Show Replace Field","depth":4,"bounds":{"left":0.60206115,"top":0.08060654,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Search History","depth":3,"bounds":{"left":0.6146942,"top":0.07980846,"width":0.00731383,"height":0.017557861},"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"Received 429 from API","depth":4,"bounds":{"left":0.6256649,"top":0.07980846,"width":0.0631649,"height":0.015961692},"on_screen":true,"value":"Received 429 from API","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"New Line","depth":3,"bounds":{"left":0.6978058,"top":0.07980846,"width":0.00731383,"height":0.017557861},"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Match Case","depth":3,"bounds":{"left":0.7077792,"top":0.07980846,"width":0.00731383,"height":0.017557861},"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Words","depth":3,"bounds":{"left":0.71642286,"top":0.07980846,"width":0.00731383,"height":0.017557861},"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Regex","depth":3,"bounds":{"left":0.7250665,"top":0.07980846,"width":0.00731383,"height":0.017557861},"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Replace History","depth":3,"bounds":{"left":0.27027926,"top":1.0,"width":0.00731383,"height":0.0},"on_screen":false,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"Replace","depth":4,"on_screen":false,"role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"New Line","depth":3,"bounds":{"left":0.27027926,"top":1.0,"width":0.00731383,"height":0.0},"on_screen":false,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Preserve case","depth":3,"bounds":{"left":0.27027926,"top":1.0,"width":0.00731383,"height":0.0},"on_screen":false,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1/5","depth":4,"bounds":{"left":0.7386968,"top":0.079010375,"width":0.025598405,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Occurrence","depth":4,"bounds":{"left":0.7642952,"top":0.07821229,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Occurrence","depth":4,"bounds":{"left":0.77293885,"top":0.07821229,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Filter Search Results","depth":4,"bounds":{"left":0.7815825,"top":0.07821229,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open in Window, Multiple Cursors","depth":4,"bounds":{"left":0.79022604,"top":0.07821229,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Click to highlight","depth":4,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":4,"bounds":{"left":0.97539896,"top":0.07821229,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"523","depth":4,"bounds":{"left":0.9601064,"top":0.10933759,"width":0.012300532,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.9740692,"top":0.10774142,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.98138297,"top":0.10774142,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"[2026-05-11 10:17:03] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":615092,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"f0becb3b-1f4f-4fb3-a311-9056fd2ae449\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:03] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":615092} {\"correlation_id\":\"f0becb3b-1f4f-4fb3-a311-9056fd2ae449\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:03] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":615092,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"f0becb3b-1f4f-4fb3-a311-9056fd2ae449\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:03] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":615092,\"participants\":[{\"id\":1004102,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1004103,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"f0becb3b-1f4f-4fb3-a311-9056fd2ae449\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:03] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"f0becb3b-1f4f-4fb3-a311-9056fd2ae449\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:03] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"f0becb3b-1f4f-4fb3-a311-9056fd2ae449\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:03] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"f0becb3b-1f4f-4fb3-a311-9056fd2ae449\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:03] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"f0becb3b-1f4f-4fb3-a311-9056fd2ae449\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:03] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"f0becb3b-1f4f-4fb3-a311-9056fd2ae449\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:03] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"nikolay.nikolov@jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/nikolay.nikolov%40jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"correlation_id\":\"f0becb3b-1f4f-4fb3-a311-9056fd2ae449\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:03] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"f0becb3b-1f4f-4fb3-a311-9056fd2ae449\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.WARNING: [Hubspot] No retry-after header or policy name found, using default {\"exception_class\":\"SevenShores\\\\Hubspot\\\\Exceptions\\\\BadRequest\"} {\"correlation_id\":\"f0becb3b-1f4f-4fb3-a311-9056fd2ae449\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.WARNING: [Hubspot] Received 429 from API {\"team_id\":2,\"config_id\":2,\"retry_after\":10,\"policy\":null,\"reason\":\"Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response:\n{\\\"status\\\":\\\"error\\\",\\\"message\\\":\\\"You have reached your secondly limit.\\\",\\\"errorType\\\":\\\"RATE_LIMIT\\\",\\\"correlationId\\\":\\\"019e168a-5 (truncated...)\n\"} {\"correlation_id\":\"f0becb3b-1f4f-4fb3-a311-9056fd2ae449\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"f0becb3b-1f4f-4fb3-a311-9056fd2ae449\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614436,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614436} {\"correlation_id\":\"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614436,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614436,\"participants\":[{\"id\":1002751,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002752,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614382,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"78f847cf-6495-4054-b3d4-e179a133bd42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614382} {\"correlation_id\":\"78f847cf-6495-4054-b3d4-e179a133bd42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614382,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"78f847cf-6495-4054-b3d4-e179a133bd42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614382,\"participants\":[{\"id\":1002632,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002633,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"78f847cf-6495-4054-b3d4-e179a133bd42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"78f847cf-6495-4054-b3d4-e179a133bd42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"78f847cf-6495-4054-b3d4-e179a133bd42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"78f847cf-6495-4054-b3d4-e179a133bd42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"78f847cf-6495-4054-b3d4-e179a133bd42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"78f847cf-6495-4054-b3d4-e179a133bd42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"78f847cf-6495-4054-b3d4-e179a133bd42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"78f847cf-6495-4054-b3d4-e179a133bd42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614381,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614381} {\"correlation_id\":\"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614381,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614381,\"participants\":[{\"id\":1002630,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002631,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614378,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":6167,\"account_id\":null,\"opportunity_id\":null,\"stage_id\":null}} {\"correlation_id\":\"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614378} {\"correlation_id\":\"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614378,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614378,\"participants\":[{\"id\":1002623,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002624,\"user_id\":null,\"contact_id\":6167,\"lead_id\":null},{\"id\":1002625,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":15} {\"correlation_id\":\"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613840,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613840} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613840,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613840,\"participants\":[{\"id\":1001764,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1001765,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: ProspectCache - Searching DB for opportunity by owner {\"account_id\":244,\"contact_id\":4487,\"owner_id\":261} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: ProspectCache - Opportunity DB search results {\"account_id\":244,\"contact_id\":4487,\"opportunity_id\":299} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613840,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613840,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613840} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613840,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613840,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613833,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"f9846f48-5841-4a71-b500-64b802c67d05\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613833} {\"correlation_id\":\"f9846f48-5841-4a71-b500-64b802c67d05\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613833,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"f9846f48-5841-4a71-b500-64b802c67d05\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613833,\"participants\":[{\"id\":1001750,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1001751,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"f9846f48-5841-4a71-b500-64b802c67d05\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"f9846f48-5841-4a71-b500-64b802c67d05\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"f9846f48-5841-4a71-b500-64b802c67d05\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"f9846f48-5841-4a71-b500-64b802c67d05\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"f9846f48-5841-4a71-b500-64b802c67d05\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"f9846f48-5841-4a71-b500-64b802c67d05\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613833,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"f9846f48-5841-4a71-b500-64b802c67d05\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613833,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"f9846f48-5841-4a71-b500-64b802c67d05\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613833} {\"correlation_id\":\"f9846f48-5841-4a71-b500-64b802c67d05\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613833,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"f9846f48-5841-4a71-b500-64b802c67d05\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613833,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"f9846f48-5841-4a71-b500-64b802c67d05\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613827,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"d060f13a-e3b7-416c-ac24-ebc305d1fd66\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613827} {\"correlation_id\":\"d060f13a-e3b7-416c-ac24-ebc305d1fd66\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613827,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"d060f13a-e3b7-416c-ac24-ebc305d1fd66\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613827,\"participants\":[{\"id\":1001734,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1001735,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"d060f13a-e3b7-416c-ac24-ebc305d1fd66\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"d060f13a-e3b7-416c-ac24-ebc305d1fd66\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"d060f13a-e3b7-416c-ac24-ebc305d1fd66\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"d060f13a-e3b7-416c-ac24-ebc305d1fd66\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"d060f13a-e3b7-416c-ac24-ebc305d1fd66\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"d060f13a-e3b7-416c-ac24-ebc305d1fd66\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613827,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"d060f13a-e3b7-416c-ac24-ebc305d1fd66\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613827,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"d060f13a-e3b7-416c-ac24-ebc305d1fd66\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613827} {\"correlation_id\":\"d060f13a-e3b7-416c-ac24-ebc305d1fd66\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613827,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"d060f13a-e3b7-416c-ac24-ebc305d1fd66\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613827,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"d060f13a-e3b7-416c-ac24-ebc305d1fd66\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613826,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613826} {\"correlation_id\":\"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613826,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613826,\"participants\":[{\"id\":1001732,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1001733,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613826,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613826,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613826} {\"correlation_id\":\"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613826,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613826,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613820,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"ee78448a-70af-4da3-a3cd-238e2067a49c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613820} {\"correlation_id\":\"ee78448a-70af-4da3-a3cd-238e2067a49c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613820,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"ee78448a-70af-4da3-a3cd-238e2067a49c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613820,\"participants\":[{\"id\":1001721,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1001722,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"ee78448a-70af-4da3-a3cd-238e2067a49c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"ee78448a-70af-4da3-a3cd-238e2067a49c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"ee78448a-70af-4da3-a3cd-238e2067a49c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"ee78448a-70af-4da3-a3cd-238e2067a49c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"ee78448a-70af-4da3-a3cd-238e2067a49c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"ee78448a-70af-4da3-a3cd-238e2067a49c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613820,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"ee78448a-70af-4da3-a3cd-238e2067a49c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613820,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"ee78448a-70af-4da3-a3cd-238e2067a49c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613820} {\"correlation_id\":\"ee78448a-70af-4da3-a3cd-238e2067a49c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613820,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"ee78448a-70af-4da3-a3cd-238e2067a49c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613820,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"ee78448a-70af-4da3-a3cd-238e2067a49c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613818,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"74704a29-86b2-4b3f-ae73-0e6d4ec1891a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613818} {\"correlation_id\":\"74704a29-86b2-4b3f-ae73-0e6d4ec1891a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613818,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"74704a29-86b2-4b3f-ae73-0e6d4ec1891a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613818,\"participants\":[{\"id\":1001717,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1001718,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"74704a29-86b2-4b3f-ae73-0e6d4ec1891a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"74704a29-86b2-4b3f-ae73-0e6d4ec1891a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"74704a29-86b2-4b3f-ae73-0e6d4ec1891a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"74704a29-86b2-4b3f-ae73-0e6d4ec1891a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"74704a29-86b2-4b3f-ae73-0e6d4ec1891a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"74704a29-86b2-4b3f-ae73-0e6d4ec1891a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613818,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"74704a29-86b2-4b3f-ae73-0e6d4ec1891a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613818,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"74704a29-86b2-4b3f-ae73-0e6d4ec1891a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613818} {\"correlation_id\":\"74704a29-86b2-4b3f-ae73-0e6d4ec1891a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613818,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"74704a29-86b2-4b3f-ae73-0e6d4ec1891a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613818,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"74704a29-86b2-4b3f-ae73-0e6d4ec1891a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613812,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"0698152e-ea7b-46d1-95e4-45730b1aac4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613812} {\"correlation_id\":\"0698152e-ea7b-46d1-95e4-45730b1aac4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613812,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"0698152e-ea7b-46d1-95e4-45730b1aac4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613812,\"participants\":[{\"id\":1001705,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1001706,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"0698152e-ea7b-46d1-95e4-45730b1aac4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"0698152e-ea7b-46d1-95e4-45730b1aac4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"0698152e-ea7b-46d1-95e4-45730b1aac4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"0698152e-ea7b-46d1-95e4-45730b1aac4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"0698152e-ea7b-46d1-95e4-45730b1aac4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"0698152e-ea7b-46d1-95e4-45730b1aac4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613812,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"0698152e-ea7b-46d1-95e4-45730b1aac4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613812,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"0698152e-ea7b-46d1-95e4-45730b1aac4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613812} {\"correlation_id\":\"0698152e-ea7b-46d1-95e4-45730b1aac4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613812,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"0698152e-ea7b-46d1-95e4-45730b1aac4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613812,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"0698152e-ea7b-46d1-95e4-45730b1aac4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613807,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4484,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613807} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613807,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613807,\"participants\":[{\"id\":1001690,\"user_id\":253,\"contact_id\":null,\"lead_id\":null},{\"id\":1001691,\"user_id\":null,\"contact_id\":4484,\"lead_id\":null}]} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613807,\"team_id\":2,\"email\":\"preslava.ivanova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: ProspectCache - Searching DB for opportunity by owner {\"account_id\":243,\"contact_id\":4484,\"owner_id\":253} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: ProspectCache - Fallback DB opportunity search {\"account_id\":243,\"contact_id\":4484} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: ProspectCache - Opportunity DB search results {\"account_id\":243,\"contact_id\":4484,\"opportunity_id\":276} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"tsvetomir.banovski@gmail.com\"} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613807,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613807} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613807,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613807,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4484,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613806,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":350,\"stage_id\":34}} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613806} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613806,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613806,\"participants\":[{\"id\":1001688,\"user_id\":253,\"contact_id\":null,\"lead_id\":null},{\"id\":1001689,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null}]} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613806,\"team_id\":2,\"email\":\"preslava.ivanova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: ProspectCache - Searching DB for opportunity by owner {\"account_id\":244,\"contact_id\":4487,\"owner_id\":253} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: ProspectCache - Fallback DB opportunity search {\"account_id\":244,\"contact_id\":4487} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: ProspectCache - Opportunity DB search results {\"account_id\":244,\"contact_id\":4487,\"opportunity_id\":350} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613806,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613806} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613806,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613806,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":350,\"stage_id\":34} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613805,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":350,\"stage_id\":34}} {\"correlation_id\":\"0d5af06d-774a-423e-8566-cb9f43e49711\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613805} {\"correlation_id\":\"0d5af06d-774a-423e-8566-cb9f43e49711\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613805,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"0d5af06d-774a-423e-8566-cb9f43e49711\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613805,\"participants\":[{\"id\":1001686,\"user_id\":253,\"contact_id\":null,\"lead_id\":null},{\"id\":1001687,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null}]} {\"correlation_id\":\"0d5af06d-774a-423e-8566-cb9f43e49711\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"0d5af06d-774a-423e-8566-cb9f43e49711\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"0d5af06d-774a-423e-8566-cb9f43e49711\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"0d5af06d-774a-423e-8566-cb9f43e49711\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"0d5af06d-774a-423e-8566-cb9f43e49711\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613805,\"team_id\":2,\"email\":\"preslava.ivanova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"0d5af06d-774a-423e-8566-cb9f43e49711\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"0d5af06d-774a-423e-8566-cb9f43e49711\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613805,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"0d5af06d-774a-423e-8566-cb9f43e49711\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613805} {\"correlation_id\":\"0d5af06d-774a-423e-8566-cb9f43e49711\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613805,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"0d5af06d-774a-423e-8566-cb9f43e49711\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613805,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":350,\"stage_id\":34} {\"correlation_id\":\"0d5af06d-774a-423e-8566-cb9f43e49711\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613698,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"80021afa-cf61-496e-89ce-8c3e54208849\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613698} {\"correlation_id\":\"80021afa-cf61-496e-89ce-8c3e54208849\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613698,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"80021afa-cf61-496e-89ce-8c3e54208849\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613698,\"participants\":[{\"id\":1001667,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1001668,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"80021afa-cf61-496e-89ce-8c3e54208849\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"80021afa-cf61-496e-89ce-8c3e54208849\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"80021afa-cf61-496e-89ce-8c3e54208849\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"80021afa-cf61-496e-89ce-8c3e54208849\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"80021afa-cf61-496e-89ce-8c3e54208849\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"80021afa-cf61-496e-89ce-8c3e54208849\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613698,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"80021afa-cf61-496e-89ce-8c3e54208849\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613698,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"80021afa-cf61-496e-89ce-8c3e54208849\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613698} {\"correlation_id\":\"80021afa-cf61-496e-89ce-8c3e54208849\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613698,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"80021afa-cf61-496e-89ce-8c3e54208849\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613698,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"80021afa-cf61-496e-89ce-8c3e54208849\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613697,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"26cb04a3-9455-48ca-bbec-d8afcaf66d89\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613697} {\"correlation_id\":\"26cb04a3-9455-48ca-bbec-d8afcaf66d89\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613697,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"26cb04a3-9455-48ca-bbec-d8afcaf66d89\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613697,\"participants\":[{\"id\":1001665,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1001666,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"26cb04a3-9455-48ca-bbec-d8afcaf66d89\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"26cb04a3-9455-48ca-bbec-d8afcaf66d89\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"26cb04a3-9455-48ca-bbec-d8afcaf66d89\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"26cb04a3-9455-48ca-bbec-d8afcaf66d89\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"26cb04a3-9455-48ca-bbec-d8afcaf66d89\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"26cb04a3-9455-48ca-bbec-d8afcaf66d89\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613697,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"26cb04a3-9455-48ca-bbec-d8afcaf66d89\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613697,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"26cb04a3-9455-48ca-bbec-d8afcaf66d89\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613697} {\"correlation_id\":\"26cb04a3-9455-48ca-bbec-d8afcaf66d89\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613697,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"26cb04a3-9455-48ca-bbec-d8afcaf66d89\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613697,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"26cb04a3-9455-48ca-bbec-d8afcaf66d89\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613696,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"1394ff3a-8967-4099-957d-78dd3bd1ad06\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613696} {\"correlation_id\":\"1394ff3a-8967-4099-957d-78dd3bd1ad06\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613696,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"1394ff3a-8967-4099-957d-78dd3bd1ad06\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613696,\"participants\":[{\"id\":1001663,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1001664,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"1394ff3a-8967-4099-957d-78dd3bd1ad06\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"1394ff3a-8967-4099-957d-78dd3bd1ad06\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"1394ff3a-8967-4099-957d-78dd3bd1ad06\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"1394ff3a-8967-4099-957d-78dd3bd1ad06\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"1394ff3a-8967-4099-957d-78dd3bd1ad06\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"1394ff3a-8967-4099-957d-78dd3bd1ad06\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613696,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"1394ff3a-8967-4099-957d-78dd3bd1ad06\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613696,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"1394ff3a-8967-4099-957d-78dd3bd1ad06\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613696} {\"correlation_id\":\"1394ff3a-8967-4099-957d-78dd3bd1ad06\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613696,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"1394ff3a-8967-4099-957d-78dd3bd1ad06\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613696,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"1394ff3a-8967-4099-957d-78dd3bd1ad06\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613695,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"8e71d37f-8fcc-4294-a951-7e7e1fa36414\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613695} {\"correlation_id\":\"8e71d37f-8fcc-4294-a951-7e7e1fa36414\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613695,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"8e71d37f-8fcc-4294-a951-7e7e1fa36414\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613695,\"participants\":[{\"id\":1001661,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1001662,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"8e71d37f-8fcc-4294-a951-7e7e1fa36414\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"8e71d37f-8fcc-4294-a951-7e7e1fa36414\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"8e71d37f-8fcc-4294-a951-7e7e1fa36414\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"8e71d37f-8fcc-4294-a951-7e7e1fa36414\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"8e71d37f-8fcc-4294-a951-7e7e1fa36414\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"8e71d37f-8fcc-4294-a951-7e7e1fa36414\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613695,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"8e71d37f-8fcc-4294-a951-7e7e1fa36414\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613695,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"8e71d37f-8fcc-4294-a951-7e7e1fa36414\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613695} {\"correlation_id\":\"8e71d37f-8fcc-4294-a951-7e7e1fa36414\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613695,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"8e71d37f-8fcc-4294-a951-7e7e1fa36414\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613695,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"8e71d37f-8fcc-4294-a951-7e7e1fa36414\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613694,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"e3d5ac8c-21da-4854-8976-7e5916c19626\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613694} {\"correlation_id\":\"e3d5ac8c-21da-4854-8976-7e5916c19626\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613694,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"e3d5ac8c-21da-4854-8976-7e5916c19626\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613694,\"participants\":[{\"id\":1001659,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1001660,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"e3d5ac8c-21da-4854-8976-7e5916c19626\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"e3d5ac8c-21da-4854-8976-7e5916c19626\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"e3d5ac8c-21da-4854-8976-7e5916c19626\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"e3d5ac8c-21da-4854-8976-7e5916c19626\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"e3d5ac8c-21da-4854-8976-7e5916c19626\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"e3d5ac8c-21da-4854-8976-7e5916c19626\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613694,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"e3d5ac8c-21da-4854-8976-7e5916c19626\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613694,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"e3d5ac8c-21da-4854-8976-7e5916c19626\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613694} {\"correlation_id\":\"e3d5ac8c-21da-4854-8976-7e5916c19626\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613694,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"e3d5ac8c-21da-4854-8976-7e5916c19626\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613694,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"e3d5ac8c-21da-4854-8976-7e5916c19626\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613157,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":350,\"stage_id\":34}} {\"correlation_id\":\"5ac0504a-ec31-4cd3-bee9-a22a17043d87\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613157} {\"correlation_id\":\"5ac0504a-ec31-4cd3-bee9-a22a17043d87\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613157,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"5ac0504a-ec31-4cd3-bee9-a22a17043d87\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613157,\"participants\":[{\"id\":1000746,\"user_id\":253,\"contact_id\":null,\"lead_id\":null},{\"id\":1000747,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null}]} {\"correlation_id\":\"5ac0504a-ec31-4cd3-bee9-a22a17043d87\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"5ac0504a-ec31-4cd3-bee9-a22a17043d87\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"5ac0504a-ec31-4cd3-bee9-a22a17043d87\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"5ac0504a-ec31-4cd3-bee9-a22a17043d87\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"5ac0504a-ec31-4cd3-bee9-a22a17043d87\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613157,\"team_id\":2,\"email\":\"preslava.ivanova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"5ac0504a-ec31-4cd3-bee9-a22a17043d87\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"5ac0504a-ec31-4cd3-bee9-a22a17043d87\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613157,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"5ac0504a-ec31-4cd3-bee9-a22a17043d87\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613157} {\"correlation_id\":\"5ac0504a-ec31-4cd3-bee9-a22a17043d87\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613157,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"5ac0504a-ec31-4cd3-bee9-a22a17043d87\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613157,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":350,\"stage_id\":34} {\"correlation_id\":\"5ac0504a-ec31-4cd3-bee9-a22a17043d87\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613156,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":350,\"stage_id\":34}} {\"correlation_id\":\"dc55bf51-23a4-467e-a0eb-e005ac332df8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613156} {\"correlation_id\":\"dc55bf51-23a4-467e-a0eb-e005ac332df8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613156,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"dc55bf51-23a4-467e-a0eb-e005ac332df8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613156,\"participants\":[{\"id\":1000744,\"user_id\":253,\"contact_id\":null,\"lead_id\":null},{\"id\":1000745,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null}]} {\"correlation_id\":\"dc55bf51-23a4-467e-a0eb-e005ac332df8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"dc55bf51-23a4-467e-a0eb-e005ac332df8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"dc55bf51-23a4-467e-a0eb-e005ac332df8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"dc55bf51-23a4-467e-a0eb-e005ac332df8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"dc55bf51-23a4-467e-a0eb-e005ac332df8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613156,\"team_id\":2,\"email\":\"preslava.ivanova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"dc55bf51-23a4-467e-a0eb-e005ac332df8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"dc55bf51-23a4-467e-a0eb-e005ac332df8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613156,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"dc55bf51-23a4-467e-a0eb-e005ac332df8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613156} {\"correlation_id\":\"dc55bf51-23a4-467e-a0eb-e005ac332df8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613156,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"dc55bf51-23a4-467e-a0eb-e005ac332df8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613156,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":350,\"stage_id\":34} {\"correlation_id\":\"dc55bf51-23a4-467e-a0eb-e005ac332df8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613155,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":350,\"stage_id\":34}} {\"correlation_id\":\"3eef285e-0d37-4ed8-b4ab-aa92cf893970\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613155} {\"correlation_id\":\"3eef285e-0d37-4ed8-b4ab-aa92cf893970\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613155,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"3eef285e-0d37-4ed8-b4ab-aa92cf893970\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613155,\"participants\":[{\"id\":1000742,\"user_id\":253,\"contact_id\":null,\"lead_id\":null},{\"id\":1000743,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null}]} {\"correlation_id\":\"3eef285e-0d37-4ed8-b4ab-aa92cf893970\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"3eef285e-0d37-4ed8-b4ab-aa92cf893970\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"3eef285e-0d37-4ed8-b4ab-aa92cf893970\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"3eef285e-0d37-4ed8-b4ab-aa92cf893970\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"3eef285e-0d37-4ed8-b4ab-aa92cf893970\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613155,\"team_id\":2,\"email\":\"preslava.ivanova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"3eef285e-0d37-4ed8-b4ab-aa92cf893970\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"3eef285e-0d37-4ed8-b4ab-aa92cf893970\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613155,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"3eef285e-0d37-4ed8-b4ab-aa92cf893970\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613155} {\"correlation_id\":\"3eef285e-0d37-4ed8-b4ab-aa92cf893970\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613155,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"3eef285e-0d37-4ed8-b4ab-aa92cf893970\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613155,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":350,\"stage_id\":34} {\"correlation_id\":\"3eef285e-0d37-4ed8-b4ab-aa92cf893970\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613130,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"3c8a085d-bdf1-40eb-a97e-a240a0d42001\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613130} {\"correlation_id\":\"3c8a085d-bdf1-40eb-a97e-a240a0d42001\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613130,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"3c8a085d-bdf1-40eb-a97e-a240a0d42001\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613130,\"participants\":[{\"id\":1000693,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1000694,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"3c8a085d-bdf1-40eb-a97e-a240a0d42001\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"3c8a085d-bdf1-40eb-a97e-a240a0d42001\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"3c8a085d-bdf1-40eb-a97e-a240a0d42001\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"3c8a085d-bdf1-40eb-a97e-a240a0d42001\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"3c8a085d-bdf1-40eb-a97e-a240a0d42001\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"3c8a085d-bdf1-40eb-a97e-a240a0d42001\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613130,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"3c8a085d-bdf1-40eb-a97e-a240a0d42001\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613130,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"3c8a085d-bdf1-40eb-a97e-a240a0d42001\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613130} {\"correlation_id\":\"3c8a085d-bdf1-40eb-a97e-a240a0d42001\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613130,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"3c8a085d-bdf1-40eb-a97e-a240a0d42001\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613130,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"3c8a085d-bdf1-40eb-a97e-a240a0d42001\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612924,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":165,\"stage_id\":89}} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612924} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612924,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612924,\"participants\":[{\"id\":1000290,\"user_id\":19,\"contact_id\":null,\"lead_id\":null},{\"id\":1000291,\"user_id\":null,\"contact_id\":97,\"lead_id\":null}]} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612924,\"team_id\":2,\"email\":\"james.graham@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: ProspectCache - Searching DB for opportunity by owner {\"account_id\":69,\"contact_id\":97,\"owner_id\":19} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: ProspectCache - Opportunity DB search results {\"account_id\":69,\"contact_id\":97,\"opportunity_id\":165} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinsoncrusoe@test.com\"} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612924,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612924} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612924,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612924,\"remote_search\":true,\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":165,\"stage_id\":89} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612923,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":165,\"stage_id\":89}} {\"correlation_id\":\"247ebe62-b545-410c-9a1a-a64a2a16f74f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612923} {\"correlation_id\":\"247ebe62-b545-410c-9a1a-a64a2a16f74f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612923,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"247ebe62-b545-410c-9a1a-a64a2a16f74f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612923,\"participants\":[{\"id\":1000288,\"user_id\":19,\"contact_id\":null,\"lead_id\":null},{\"id\":1000289,\"user_id\":null,\"contact_id\":97,\"lead_id\":null}]} {\"correlation_id\":\"247ebe62-b545-410c-9a1a-a64a2a16f74f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"247ebe62-b545-410c-9a1a-a64a2a16f74f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"247ebe62-b545-410c-9a1a-a64a2a16f74f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"247ebe62-b545-410c-9a1a-a64a2a16f74f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"247ebe62-b545-410c-9a1a-a64a2a16f74f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612923,\"team_id\":2,\"email\":\"james.graham@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"247ebe62-b545-410c-9a1a-a64a2a16f74f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinsoncrusoe@test.com\"} {\"correlation_id\":\"247ebe62-b545-410c-9a1a-a64a2a16f74f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612923,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"247ebe62-b545-410c-9a1a-a64a2a16f74f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612923} {\"correlation_id\":\"247ebe62-b545-410c-9a1a-a64a2a16f74f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612923,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"247ebe62-b545-410c-9a1a-a64a2a16f74f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612923,\"remote_search\":true,\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":165,\"stage_id\":89} {\"correlation_id\":\"247ebe62-b545-410c-9a1a-a64a2a16f74f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612922,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":165,\"stage_id\":89}} {\"correlation_id\":\"8eec93ee-21ff-4839-8d92-4c5e73e5cb02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612922} {\"correlation_id\":\"8eec93ee-21ff-4839-8d92-4c5e73e5cb02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612922,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"8eec93ee-21ff-4839-8d92-4c5e73e5cb02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612922,\"participants\":[{\"id\":1000286,\"user_id\":19,\"contact_id\":null,\"lead_id\":null},{\"id\":1000287,\"user_id\":null,\"contact_id\":97,\"lead_id\":null}]} {\"correlation_id\":\"8eec93ee-21ff-4839-8d92-4c5e73e5cb02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"8eec93ee-21ff-4839-8d92-4c5e73e5cb02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"8eec93ee-21ff-4839-8d92-4c5e73e5cb02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"8eec93ee-21ff-4839-8d92-4c5e73e5cb02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"8eec93ee-21ff-4839-8d92-4c5e73e5cb02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612922,\"team_id\":2,\"email\":\"james.graham@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"8eec93ee-21ff-4839-8d92-4c5e73e5cb02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinsoncrusoe@test.com\"} {\"correlation_id\":\"8eec93ee-21ff-4839-8d92-4c5e73e5cb02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612922,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"8eec93ee-21ff-4839-8d92-4c5e73e5cb02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612922} {\"correlation_id\":\"8eec93ee-21ff-4839-8d92-4c5e73e5cb02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612922,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"8eec93ee-21ff-4839-8d92-4c5e73e5cb02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612922,\"remote_search\":true,\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":165,\"stage_id\":89} {\"correlation_id\":\"8eec93ee-21ff-4839-8d92-4c5e73e5cb02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612847,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"e1add09a-4136-4471-aaab-635ce3913944\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612847} {\"correlation_id\":\"e1add09a-4136-4471-aaab-635ce3913944\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612847,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"e1add09a-4136-4471-aaab-635ce3913944\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612847,\"participants\":[{\"id\":1000130,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1000131,\"user_id\":261,\"contact_id\":null,\"lead_id\":null},{\"id\":1000151,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null}]} {\"correlation_id\":\"e1add09a-4136-4471-aaab-635ce3913944\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"e1add09a-4136-4471-aaab-635ce3913944\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"e1add09a-4136-4471-aaab-635ce3913944\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"e1add09a-4136-4471-aaab-635ce3913944\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"e1add09a-4136-4471-aaab-635ce3913944\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"correlation_id\":\"e1add09a-4136-4471-aaab-635ce3913944\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"adelina.petrova@jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/adelina.petrova%40jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"correlation_id\":\"e1add09a-4136-4471-aaab-635ce3913944\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"correlation_id\":\"e1add09a-4136-4471-aaab-635ce3913944\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"e1add09a-4136-4471-aaab-635ce3913944\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612822,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"0dc18256-a5c4-4809-8f4f-ae8acfa1c62a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612822} {\"correlation_id\":\"0dc18256-a5c4-4809-8f4f-ae8acfa1c62a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612822,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"0dc18256-a5c4-4809-8f4f-ae8acfa1c62a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612822,\"participants\":[{\"id\":1000080,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1000081,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"0dc18256-a5c4-4809-8f4f-ae8acfa1c62a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"0dc18256-a5c4-4809-8f4f-ae8acfa1c62a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"0dc18256-a5c4-4809-8f4f-ae8acfa1c62a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"0dc18256-a5c4-4809-8f4f-ae8acfa1c62a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"0dc18256-a5c4-4809-8f4f-ae8acfa1c62a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"0dc18256-a5c4-4809-8f4f-ae8acfa1c62a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612822,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"0dc18256-a5c4-4809-8f4f-ae8acfa1c62a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612822,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"0dc18256-a5c4-4809-8f4f-ae8acfa1c62a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612822} {\"correlation_id\":\"0dc18256-a5c4-4809-8f4f-ae8acfa1c62a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612822,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"0dc18256-a5c4-4809-8f4f-ae8acfa1c62a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612822,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"0dc18256-a5c4-4809-8f4f-ae8acfa1c62a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612819,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"fc4dcdd9-0121-448e-8b4e-fc0e39d20a72\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612819} {\"correlation_id\":\"fc4dcdd9-0121-448e-8b4e-fc0e39d20a72\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612819,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"fc4dcdd9-0121-448e-8b4e-fc0e39d20a72\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612819,\"participants\":[{\"id\":1000073,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1000074,\"user_id\":261,\"contact_id\":null,\"lead_id\":null},{\"id\":1000075,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"fc4dcdd9-0121-448e-8b4e-fc0e39d20a72\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"fc4dcdd9-0121-448e-8b4e-fc0e39d20a72\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"fc4dcdd9-0121-448e-8b4e-fc0e39d20a72\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"fc4dcdd9-0121-448e-8b4e-fc0e39d20a72\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"fc4dcdd9-0121-448e-8b4e-fc0e39d20a72\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"fc4dcdd9-0121-448e-8b4e-fc0e39d20a72\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612819,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"fc4dcdd9-0121-448e-8b4e-fc0e39d20a72\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"correlation_id\":\"fc4dcdd9-0121-448e-8b4e-fc0e39d20a72\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"correlation_id\":\"fc4dcdd9-0121-448e-8b4e-fc0e39d20a72\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"fc4dcdd9-0121-448e-8b4e-fc0e39d20a72\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612673,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"8b734f7b-ff76-4bcd-b217-f33580cc5d42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612673} {\"correlation_id\":\"8b734f7b-ff76-4bcd-b217-f33580cc5d42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612673,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"8b734f7b-ff76-4bcd-b217-f33580cc5d42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612673,\"participants\":[{\"id\":999993,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":999994,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"8b734f7b-ff76-4bcd-b217-f33580cc5d42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"8b734f7b-ff76-4bcd-b217-f33580cc5d42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"8b734f7b-ff76-4bcd-b217-f33580cc5d42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"8b734f7b-ff76-4bcd-b217-f33580cc5d42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"8b734f7b-ff76-4bcd-b217-f33580cc5d42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"8b734f7b-ff76-4bcd-b217-f33580cc5d42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612673,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"8b734f7b-ff76-4bcd-b217-f33580cc5d42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612673,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"8b734f7b-ff76-4bcd-b217-f33580cc5d42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612673} {\"correlation_id\":\"8b734f7b-ff76-4bcd-b217-f33580cc5d42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612673,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"8b734f7b-ff76-4bcd-b217-f33580cc5d42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612673,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"8b734f7b-ff76-4bcd-b217-f33580cc5d42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612642,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"ba79ca47-b56d-4686-9d40-25f98db53e2d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612642} {\"correlation_id\":\"ba79ca47-b56d-4686-9d40-25f98db53e2d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612642,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"ba79ca47-b56d-4686-9d40-25f98db53e2d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612642,\"participants\":[{\"id\":999935,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":999936,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"ba79ca47-b56d-4686-9d40-25f98db53e2d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"ba79ca47-b56d-4686-9d40-25f98db53e2d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"ba79ca47-b56d-4686-9d40-25f98db53e2d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"ba79ca47-b56d-4686-9d40-25f98db53e2d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"ba79ca47-b56d-4686-9d40-25f98db53e2d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"ba79ca47-b56d-4686-9d40-25f98db53e2d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612642,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"ba79ca47-b56d-4686-9d40-25f98db53e2d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612642,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"ba79ca47-b56d-4686-9d40-25f98db53e2d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612642} {\"correlation_id\":\"ba79ca47-b56d-4686-9d40-25f98db53e2d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612642,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"ba79ca47-b56d-4686-9d40-25f98db53e2d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612642,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"ba79ca47-b56d-4686-9d40-25f98db53e2d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612598,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612598} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612598,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612598,\"participants\":[{\"id\":999857,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999858,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: ProspectCache - Searching DB for opportunity by owner {\"account_id\":243,\"contact_id\":4491,\"owner_id\":206} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: ProspectCache - Fallback DB opportunity search {\"account_id\":243,\"contact_id\":4491} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: ProspectCache - Opportunity DB search results {\"account_id\":243,\"contact_id\":4491,\"opportunity_id\":276} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612598,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612598,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612598} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612598,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612598,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612597,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"62c5275c-1274-41ee-bc3f-5bbf783b9e37\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612597} {\"correlation_id\":\"62c5275c-1274-41ee-bc3f-5bbf783b9e37\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612597,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"62c5275c-1274-41ee-bc3f-5bbf783b9e37\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612597,\"participants\":[{\"id\":999855,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999856,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null}]} {\"correlation_id\":\"62c5275c-1274-41ee-bc3f-5bbf783b9e37\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"62c5275c-1274-41ee-bc3f-5bbf783b9e37\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"62c5275c-1274-41ee-bc3f-5bbf783b9e37\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"62c5275c-1274-41ee-bc3f-5bbf783b9e37\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"62c5275c-1274-41ee-bc3f-5bbf783b9e37\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612597,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"62c5275c-1274-41ee-bc3f-5bbf783b9e37\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"62c5275c-1274-41ee-bc3f-5bbf783b9e37\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612597,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"62c5275c-1274-41ee-bc3f-5bbf783b9e37\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612597} {\"correlation_id\":\"62c5275c-1274-41ee-bc3f-5bbf783b9e37\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612597,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"62c5275c-1274-41ee-bc3f-5bbf783b9e37\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612597,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"62c5275c-1274-41ee-bc3f-5bbf783b9e37\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612596,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"c07694f1-899f-4ac8-be40-e00a204aac88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612596} {\"correlation_id\":\"c07694f1-899f-4ac8-be40-e00a204aac88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612596,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"c07694f1-899f-4ac8-be40-e00a204aac88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612596,\"participants\":[{\"id\":999853,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999854,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null}]} {\"correlation_id\":\"c07694f1-899f-4ac8-be40-e00a204aac88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"c07694f1-899f-4ac8-be40-e00a204aac88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"c07694f1-899f-4ac8-be40-e00a204aac88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"c07694f1-899f-4ac8-be40-e00a204aac88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"c07694f1-899f-4ac8-be40-e00a204aac88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612596,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"c07694f1-899f-4ac8-be40-e00a204aac88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"c07694f1-899f-4ac8-be40-e00a204aac88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612596,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"c07694f1-899f-4ac8-be40-e00a204aac88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612596} {\"correlation_id\":\"c07694f1-899f-4ac8-be40-e00a204aac88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612596,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"c07694f1-899f-4ac8-be40-e00a204aac88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612596,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"c07694f1-899f-4ac8-be40-e00a204aac88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612595,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"a42bd4c7-5a99-40a1-8f2d-310dc2de3d2e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612595} {\"correlation_id\":\"a42bd4c7-5a99-40a1-8f2d-310dc2de3d2e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612595,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"a42bd4c7-5a99-40a1-8f2d-310dc2de3d2e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612595,\"participants\":[{\"id\":999851,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999852,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"a42bd4c7-5a99-40a1-8f2d-310dc2de3d2e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"a42bd4c7-5a99-40a1-8f2d-310dc2de3d2e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"a42bd4c7-5a99-40a1-8f2d-310dc2de3d2e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"a42bd4c7-5a99-40a1-8f2d-310dc2de3d2e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"a42bd4c7-5a99-40a1-8f2d-310dc2de3d2e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"a42bd4c7-5a99-40a1-8f2d-310dc2de3d2e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612595,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"a42bd4c7-5a99-40a1-8f2d-310dc2de3d2e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612595,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"a42bd4c7-5a99-40a1-8f2d-310dc2de3d2e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612595} {\"correlation_id\":\"a42bd4c7-5a99-40a1-8f2d-310dc2de3d2e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612595,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"a42bd4c7-5a99-40a1-8f2d-310dc2de3d2e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612595,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"a42bd4c7-5a99-40a1-8f2d-310dc2de3d2e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612594,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"bb1f8c52-2f4c-4c3b-b77f-4f1a1bb3109d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612594} {\"correlation_id\":\"bb1f8c52-2f4c-4c3b-b77f-4f1a1bb3109d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612594,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"bb1f8c52-2f4c-4c3b-b77f-4f1a1bb3109d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612594,\"participants\":[{\"id\":999849,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999850,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null}]} {\"correlation_id\":\"bb1f8c52-2f4c-4c3b-b77f-4f1a1bb3109d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"bb1f8c52-2f4c-4c3b-b77f-4f1a1bb3109d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"bb1f8c52-2f4c-4c3b-b77f-4f1a1bb3109d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"bb1f8c52-2f4c-4c3b-b77f-4f1a1bb3109d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"bb1f8c52-2f4c-4c3b-b77f-4f1a1bb3109d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612594,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"bb1f8c52-2f4c-4c3b-b77f-4f1a1bb3109d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"bb1f8c52-2f4c-4c3b-b77f-4f1a1bb3109d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612594,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"bb1f8c52-2f4c-4c3b-b77f-4f1a1bb3109d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612594} {\"correlation_id\":\"bb1f8c52-2f4c-4c3b-b77f-4f1a1bb3109d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612594,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"bb1f8c52-2f4c-4c3b-b77f-4f1a1bb3109d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612594,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"bb1f8c52-2f4c-4c3b-b77f-4f1a1bb3109d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612593,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"4d5f5c05-bcfd-478f-aa51-3301a9db49f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612593} {\"correlation_id\":\"4d5f5c05-bcfd-478f-aa51-3301a9db49f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612593,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"4d5f5c05-bcfd-478f-aa51-3301a9db49f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612593,\"participants\":[{\"id\":999847,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999848,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null}]} {\"correlation_id\":\"4d5f5c05-bcfd-478f-aa51-3301a9db49f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4d5f5c05-bcfd-478f-aa51-3301a9db49f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4d5f5c05-bcfd-478f-aa51-3301a9db49f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"4d5f5c05-bcfd-478f-aa51-3301a9db49f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"4d5f5c05-bcfd-478f-aa51-3301a9db49f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612593,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"4d5f5c05-bcfd-478f-aa51-3301a9db49f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"4d5f5c05-bcfd-478f-aa51-3301a9db49f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612593,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"4d5f5c05-bcfd-478f-aa51-3301a9db49f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612593} {\"correlation_id\":\"4d5f5c05-bcfd-478f-aa51-3301a9db49f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612593,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"4d5f5c05-bcfd-478f-aa51-3301a9db49f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612593,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"4d5f5c05-bcfd-478f-aa51-3301a9db49f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612592,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"a80a8412-d94f-42a6-b884-72c206ac1da4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612592} {\"correlation_id\":\"a80a8412-d94f-42a6-b884-72c206ac1da4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612592,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"a80a8412-d94f-42a6-b884-72c206ac1da4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612592,\"participants\":[{\"id\":999845,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999846,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"a80a8412-d94f-42a6-b884-72c206ac1da4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"a80a8412-d94f-42a6-b884-72c206ac1da4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"4a8732a4-99b7-41d1-b7b2-eca5b5e48e29\",\"trace_id\":\"61c44eed-65c5-4e52-a175-3bee690af53c\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"a80a8412-d94f-42a6-b884-72c206ac1da4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"a80a8412-d94f-42a6-b884-72c206ac1da4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"a80a8412-d94f-42a6-b884-72c206ac1da4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"a80a8412-d94f-42a6-b884-72c206ac1da4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612592,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"a80a8412-d94f-42a6-b884-72c206ac1da4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612592,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"a80a8412-d94f-42a6-b884-72c206ac1da4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612592} {\"correlation_id\":\"a80a8412-d94f-42a6-b884-72c206ac1da4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612592,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"a80a8412-d94f-42a6-b884-72c206ac1da4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612592,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"a80a8412-d94f-42a6-b884-72c206ac1da4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ScheduleBotCommand] Number of activities to be captured: 0 {\"correlation_id\":\"4a8732a4-99b7-41d1-b7b2-eca5b5e48e29\",\"trace_id\":\"61c44eed-65c5-4e52-a175-3bee690af53c\"}\n[2026-05-11 10:17:07] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"4a8732a4-99b7-41d1-b7b2-eca5b5e48e29\",\"trace_id\":\"61c44eed-65c5-4e52-a175-3bee690af53c\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612591,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"227671e6-a371-4f4c-b68e-79cfc8a40b80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612591} {\"correlation_id\":\"227671e6-a371-4f4c-b68e-79cfc8a40b80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612591,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"227671e6-a371-4f4c-b68e-79cfc8a40b80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612591,\"participants\":[{\"id\":999843,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999844,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null}]} {\"correlation_id\":\"227671e6-a371-4f4c-b68e-79cfc8a40b80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"227671e6-a371-4f4c-b68e-79cfc8a40b80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"227671e6-a371-4f4c-b68e-79cfc8a40b80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"227671e6-a371-4f4c-b68e-79cfc8a40b80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"227671e6-a371-4f4c-b68e-79cfc8a40b80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612591,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"227671e6-a371-4f4c-b68e-79cfc8a40b80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"227671e6-a371-4f4c-b68e-79cfc8a40b80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612591,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"227671e6-a371-4f4c-b68e-79cfc8a40b80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612591} {\"correlation_id\":\"227671e6-a371-4f4c-b68e-79cfc8a40b80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612591,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"227671e6-a371-4f4c-b68e-79cfc8a40b80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612591,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"227671e6-a371-4f4c-b68e-79cfc8a40b80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612590,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"b0316038-52d2-4649-bbfd-3398e4ba616c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612590} {\"correlation_id\":\"b0316038-52d2-4649-bbfd-3398e4ba616c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612590,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"b0316038-52d2-4649-bbfd-3398e4ba616c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612590,\"participants\":[{\"id\":999841,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999842,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null}]} {\"correlation_id\":\"b0316038-52d2-4649-bbfd-3398e4ba616c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b0316038-52d2-4649-bbfd-3398e4ba616c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b0316038-52d2-4649-bbfd-3398e4ba616c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"b0316038-52d2-4649-bbfd-3398e4ba616c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"b0316038-52d2-4649-bbfd-3398e4ba616c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612590,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"b0316038-52d2-4649-bbfd-3398e4ba616c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"b0316038-52d2-4649-bbfd-3398e4ba616c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612590,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"b0316038-52d2-4649-bbfd-3398e4ba616c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612590} {\"correlation_id\":\"b0316038-52d2-4649-bbfd-3398e4ba616c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612590,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"b0316038-52d2-4649-bbfd-3398e4ba616c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612590,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"b0316038-52d2-4649-bbfd-3398e4ba616c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612589,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"8d0009ec-aa6b-43eb-b5e9-9fdebab1bc88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612589} {\"correlation_id\":\"8d0009ec-aa6b-43eb-b5e9-9fdebab1bc88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612589,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"8d0009ec-aa6b-43eb-b5e9-9fdebab1bc88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612589,\"participants\":[{\"id\":999839,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999840,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null}]} {\"correlation_id\":\"8d0009ec-aa6b-43eb-b5e9-9fdebab1bc88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"8d0009ec-aa6b-43eb-b5e9-9fdebab1bc88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"8d0009ec-aa6b-43eb-b5e9-9fdebab1bc88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"8d0009ec-aa6b-43eb-b5e9-9fdebab1bc88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"8d0009ec-aa6b-43eb-b5e9-9fdebab1bc88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612589,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"8d0009ec-aa6b-43eb-b5e9-9fdebab1bc88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"8d0009ec-aa6b-43eb-b5e9-9fdebab1bc88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612589,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"8d0009ec-aa6b-43eb-b5e9-9fdebab1bc88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612589} {\"correlation_id\":\"8d0009ec-aa6b-43eb-b5e9-9fdebab1bc88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612589,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"8d0009ec-aa6b-43eb-b5e9-9fdebab1bc88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612589,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"8d0009ec-aa6b-43eb-b5e9-9fdebab1bc88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612588,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"3759f33f-9281-45e5-82c7-b8232490ee14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612588} {\"correlation_id\":\"3759f33f-9281-45e5-82c7-b8232490ee14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612588,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"3759f33f-9281-45e5-82c7-b8232490ee14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612588,\"participants\":[{\"id\":999837,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999838,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"3759f33f-9281-45e5-82c7-b8232490ee14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"3759f33f-9281-45e5-82c7-b8232490ee14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"3759f33f-9281-45e5-82c7-b8232490ee14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"3759f33f-9281-45e5-82c7-b8232490ee14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"3759f33f-9281-45e5-82c7-b8232490ee14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"3759f33f-9281-45e5-82c7-b8232490ee14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612588,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"3759f33f-9281-45e5-82c7-b8232490ee14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612588,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"3759f33f-9281-45e5-82c7-b8232490ee14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612588} {\"correlation_id\":\"3759f33f-9281-45e5-82c7-b8232490ee14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612588,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"3759f33f-9281-45e5-82c7-b8232490ee14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612588,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"3759f33f-9281-45e5-82c7-b8232490ee14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612587,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"e1fd0d0c-ddd7-483c-a454-704b27f83a35\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612587} {\"correlation_id\":\"e1fd0d0c-ddd7-483c-a454-704b27f83a35\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612587,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"e1fd0d0c-ddd7-483c-a454-704b27f83a35\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612587,\"participants\":[{\"id\":999835,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999836,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null}]} {\"correlation_id\":\"e1fd0d0c-ddd7-483c-a454-704b27f83a35\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"e1fd0d0c-ddd7-483c-a454-704b27f83a35\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"e1fd0d0c-ddd7-483c-a454-704b27f83a35\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"e1fd0d0c-ddd7-483c-a454-704b27f83a35\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"e1fd0d0c-ddd7-483c-a454-704b27f83a35\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612587,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"e1fd0d0c-ddd7-483c-a454-704b27f83a35\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"e1fd0d0c-ddd7-483c-a454-704b27f83a35\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612587,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"e1fd0d0c-ddd7-483c-a454-704b27f83a35\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612587} {\"correlation_id\":\"e1fd0d0c-ddd7-483c-a454-704b27f83a35\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612587,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"e1fd0d0c-ddd7-483c-a454-704b27f83a35\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612587,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"e1fd0d0c-ddd7-483c-a454-704b27f83a35\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612586,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"65015bee-210a-4abd-ae8e-9b347db68ce5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612586} {\"correlation_id\":\"65015bee-210a-4abd-ae8e-9b347db68ce5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612586,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"65015bee-210a-4abd-ae8e-9b347db68ce5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612586,\"participants\":[{\"id\":999833,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999834,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"65015bee-210a-4abd-ae8e-9b347db68ce5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"65015bee-210a-4abd-ae8e-9b347db68ce5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"65015bee-210a-4abd-ae8e-9b347db68ce5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"65015bee-210a-4abd-ae8e-9b347db68ce5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"65015bee-210a-4abd-ae8e-9b347db68ce5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"65015bee-210a-4abd-ae8e-9b347db68ce5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612586,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"65015bee-210a-4abd-ae8e-9b347db68ce5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612586,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"65015bee-210a-4abd-ae8e-9b347db68ce5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612586} {\"correlation_id\":\"65015bee-210a-4abd-ae8e-9b347db68ce5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612586,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"65015bee-210a-4abd-ae8e-9b347db68ce5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612586,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"65015bee-210a-4abd-ae8e-9b347db68ce5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612585,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"03c44248-e58c-4287-8e6d-5c619c6fb75f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612585} {\"correlation_id\":\"03c44248-e58c-4287-8e6d-5c619c6fb75f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612585,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"03c44248-e58c-4287-8e6d-5c619c6fb75f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612585,\"participants\":[{\"id\":999831,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999832,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null}]} {\"correlation_id\":\"03c44248-e58c-4287-8e6d-5c619c6fb75f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"03c44248-e58c-4287-8e6d-5c619c6fb75f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"03c44248-e58c-4287-8e6d-5c619c6fb75f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"03c44248-e58c-4287-8e6d-5c619c6fb75f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"03c44248-e58c-4287-8e6d-5c619c6fb75f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612585,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"03c44248-e58c-4287-8e6d-5c619c6fb75f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"03c44248-e58c-4287-8e6d-5c619c6fb75f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612585,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"03c44248-e58c-4287-8e6d-5c619c6fb75f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612585} {\"correlation_id\":\"03c44248-e58c-4287-8e6d-5c619c6fb75f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612585,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"03c44248-e58c-4287-8e6d-5c619c6fb75f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612585,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"03c44248-e58c-4287-8e6d-5c619c6fb75f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612584,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"23ed7387-c743-4302-9b44-8d9813be4fe5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612584} {\"correlation_id\":\"23ed7387-c743-4302-9b44-8d9813be4fe5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612584,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"23ed7387-c743-4302-9b44-8d9813be4fe5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612584,\"participants\":[{\"id\":999829,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999830,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null}]} {\"correlation_id\":\"23ed7387-c743-4302-9b44-8d9813be4fe5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"23ed7387-c743-4302-9b44-8d9813be4fe5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"23ed7387-c743-4302-9b44-8d9813be4fe5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"23ed7387-c743-4302-9b44-8d9813be4fe5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"23ed7387-c743-4302-9b44-8d9813be4fe5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612584,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"23ed7387-c743-4302-9b44-8d9813be4fe5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"23ed7387-c743-4302-9b44-8d9813be4fe5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612584,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"23ed7387-c743-4302-9b44-8d9813be4fe5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612584} {\"correlation_id\":\"23ed7387-c743-4302-9b44-8d9813be4fe5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612584,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"23ed7387-c743-4302-9b44-8d9813be4fe5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612584,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"23ed7387-c743-4302-9b44-8d9813be4fe5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612583,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"aeabaf4b-f18e-43fd-aefc-396f54ca6ec9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612583} {\"correlation_id\":\"aeabaf4b-f18e-43fd-aefc-396f54ca6ec9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612583,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"aeabaf4b-f18e-43fd-aefc-396f54ca6ec9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612583,\"participants\":[{\"id\":999827,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999828,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"aeabaf4b-f18e-43fd-aefc-396f54ca6ec9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"aeabaf4b-f18e-43fd-aefc-396f54ca6ec9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"aeabaf4b-f18e-43fd-aefc-396f54ca6ec9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"aeabaf4b-f18e-43fd-aefc-396f54ca6ec9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"aeabaf4b-f18e-43fd-aefc-396f54ca6ec9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"aeabaf4b-f18e-43fd-aefc-396f54ca6ec9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612583,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"aeabaf4b-f18e-43fd-aefc-396f54ca6ec9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612583,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"aeabaf4b-f18e-43fd-aefc-396f54ca6ec9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612583} {\"correlation_id\":\"aeabaf4b-f18e-43fd-aefc-396f54ca6ec9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612583,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"aeabaf4b-f18e-43fd-aefc-396f54ca6ec9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612583,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"aeabaf4b-f18e-43fd-aefc-396f54ca6ec9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612582,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"522ee9f2-8c92-480b-acda-f4759553f0b0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612582} {\"correlation_id\":\"522ee9f2-8c92-480b-acda-f4759553f0b0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612582,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"522ee9f2-8c92-480b-acda-f4759553f0b0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612582,\"participants\":[{\"id\":999825,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999826,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null}]} {\"correlation_id\":\"522ee9f2-8c92-480b-acda-f4759553f0b0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"522ee9f2-8c92-480b-acda-f4759553f0b0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"522ee9f2-8c92-480b-acda-f4759553f0b0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"522ee9f2-8c92-480b-acda-f4759553f0b0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"522ee9f2-8c92-480b-acda-f4759553f0b0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612582,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"522ee9f2-8c92-480b-acda-f4759553f0b0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"522ee9f2-8c92-480b-acda-f4759553f0b0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612582,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"522ee9f2-8c92-480b-acda-f4759553f0b0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612582} {\"correlation_id\":\"522ee9f2-8c92-480b-acda-f4759553f0b0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612582,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"522ee9f2-8c92-480b-acda-f4759553f0b0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612582,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"522ee9f2-8c92-480b-acda-f4759553f0b0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612581,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"8b4434a0-8bca-4ffb-9883-31415fdcd948\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612581} {\"correlation_id\":\"8b4434a0-8bca-4ffb-9883-31415fdcd948\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612581,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"8b4434a0-8bca-4ffb-9883-31415fdcd948\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612581,\"participants\":[{\"id\":999823,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999824,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"8b4434a0-8bca-4ffb-9883-31415fdcd948\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"8b4434a0-8bca-4ffb-9883-31415fdcd948\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"8b4434a0-8bca-4ffb-9883-31415fdcd948\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"8b4434a0-8bca-4ffb-9883-31415fdcd948\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"8b4434a0-8bca-4ffb-9883-31415fdcd948\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"8b4434a0-8bca-4ffb-9883-31415fdcd948\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612581,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"8b4434a0-8bca-4ffb-9883-31415fdcd948\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612581,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"8b4434a0-8bca-4ffb-9883-31415fdcd948\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612581} {\"correlation_id\":\"8b4434a0-8bca-4ffb-9883-31415fdcd948\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612581,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"8b4434a0-8bca-4ffb-9883-31415fdcd948\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612581,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"8b4434a0-8bca-4ffb-9883-31415fdcd948\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612565,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"ff0483e4-50c5-4943-9ac0-1521c68a84a6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612565} {\"correlation_id\":\"ff0483e4-50c5-4943-9ac0-1521c68a84a6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612565,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"ff0483e4-50c5-4943-9ac0-1521c68a84a6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612565,\"participants\":[{\"id\":999789,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999790,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null}]} {\"correlation_id\":\"ff0483e4-50c5-4943-9ac0-1521c68a84a6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"ff0483e4-50c5-4943-9ac0-1521c68a84a6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"ff0483e4-50c5-4943-9ac0-1521c68a84a6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"ff0483e4-50c5-4943-9ac0-1521c68a84a6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"ff0483e4-50c5-4943-9ac0-1521c68a84a6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612565,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"ff0483e4-50c5-4943-9ac0-1521c68a84a6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"ff0483e4-50c5-4943-9ac0-1521c68a84a6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612565,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"ff0483e4-50c5-4943-9ac0-1521c68a84a6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612565} {\"correlation_id\":\"ff0483e4-50c5-4943-9ac0-1521c68a84a6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612565,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"ff0483e4-50c5-4943-9ac0-1521c68a84a6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612565,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"ff0483e4-50c5-4943-9ac0-1521c68a84a6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612563,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":350,\"stage_id\":34}} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612563} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612563,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612563,\"participants\":[{\"id\":999784,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999785,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null}]} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612563,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: ProspectCache - Searching DB for opportunity by owner {\"account_id\":244,\"contact_id\":4487,\"owner_id\":206} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: ProspectCache - Fallback DB opportunity search {\"account_id\":244,\"contact_id\":4487} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: ProspectCache - Opportunity DB search results {\"account_id\":244,\"contact_id\":4487,\"opportunity_id\":350} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612563,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612563} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612563,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612563,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":350,\"stage_id\":34} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612562,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"b3bfac4d-fb8a-4113-a07a-e949910a9e3f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612562} {\"correlation_id\":\"b3bfac4d-fb8a-4113-a07a-e949910a9e3f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612562,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"b3bfac4d-fb8a-4113-a07a-e949910a9e3f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612562,\"participants\":[{\"id\":999782,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999783,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"b3bfac4d-fb8a-4113-a07a-e949910a9e3f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b3bfac4d-fb8a-4113-a07a-e949910a9e3f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b3bfac4d-fb8a-4113-a07a-e949910a9e3f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"b3bfac4d-fb8a-4113-a07a-e949910a9e3f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"b3bfac4d-fb8a-4113-a07a-e949910a9e3f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"correlation_id\":\"b3bfac4d-fb8a-4113-a07a-e949910a9e3f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"447782589921@txt.staging.jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/447782589921%40txt.staging.jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"correlation_id\":\"b3bfac4d-fb8a-4113-a07a-e949910a9e3f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"correlation_id\":\"b3bfac4d-fb8a-4113-a07a-e949910a9e3f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":10} {\"correlation_id\":\"b3bfac4d-fb8a-4113-a07a-e949910a9e3f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612561,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"093de884-5d00-46dd-8202-1f6294142ac4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612561} {\"correlation_id\":\"093de884-5d00-46dd-8202-1f6294142ac4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612561,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"093de884-5d00-46dd-8202-1f6294142ac4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612561,\"participants\":[{\"id\":999780,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999781,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"093de884-5d00-46dd-8202-1f6294142ac4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"093de884-5d00-46dd-8202-1f6294142ac4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"093de884-5d00-46dd-8202-1f6294142ac4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"093de884-5d00-46dd-8202-1f6294142ac4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"093de884-5d00-46dd-8202-1f6294142ac4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612561,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"093de884-5d00-46dd-8202-1f6294142ac4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"447700174614.447782589921.OeREojLVnk@txt.staging.jiminny.com\"} {\"correlation_id\":\"093de884-5d00-46dd-8202-1f6294142ac4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:11] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"447700174614.447782589921.OeREojLVnk@txt.staging.jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/447700174614.447782589921.OeREojLVnk%40txt.staging.jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"correlation_id\":\"093de884-5d00-46dd-8202-1f6294142ac4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:11] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"447700174614.447782589921.OeREojLVnk@txt.staging.jiminny.com\"} {\"correlation_id\":\"093de884-5d00-46dd-8202-1f6294142ac4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:11] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":13} {\"correlation_id\":\"093de884-5d00-46dd-8202-1f6294142ac4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:12] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612560,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"55d42510-0a7f-49da-92bb-3d7d04f519e0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:12] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612560} {\"correlation_id\":\"55d42510-0a7f-49da-92bb-3d7d04f519e0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:12] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612560,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"55d42510-0a7f-49da-92bb-3d7d04f519e0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:12] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612560,\"participants\":[{\"id\":999778,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999779,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"55d42510-0a7f-49da-92bb-3d7d04f519e0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:12] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"55d42510-0a7f-49da-92bb-3d7d04f519e0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:12] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"55d42510-0a7f-49da-92bb-3d7d04f519e0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:12] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"55d42510-0a7f-49da-92bb-3d7d04f519e0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:12] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"55d42510-0a7f-49da-92bb-3d7d04f519e0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:12] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"correlation_id\":\"55d42510-0a7f-49da-92bb-3d7d04f519e0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:12] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"correlation_id\":\"55d42510-0a7f-49da-92bb-3d7d04f519e0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:12] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"55d42510-0a7f-49da-92bb-3d7d04f519e0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612559,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34}} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612559} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612559,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612559,\"participants\":[{\"id\":999776,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999777,\"user_id\":null,\"contact_id\":97,\"lead_id\":null}]} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612559,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: ProspectCache - Searching DB for opportunity by owner {\"account_id\":69,\"contact_id\":97,\"owner_id\":206} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: ProspectCache - Fallback DB opportunity search {\"account_id\":69,\"contact_id\":97} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: ProspectCache - Opportunity DB search results {\"account_id\":69,\"contact_id\":97,\"opportunity_id\":5011} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinsoncrusoe@test.com\"} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612559,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612559} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612559,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612559,\"remote_search\":true,\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:14] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612558,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34}} {\"correlation_id\":\"87d35b30-46fd-4cbe-815e-3c7fc0873c55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:14] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612558} {\"correlation_id\":\"87d35b30-46fd-4cbe-815e-3c7fc0873c55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:14] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612558,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"87d35b30-46fd-4cbe-815e-3c7fc0873c55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:14] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612558,\"participants\":[{\"id\":999774,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999775,\"user_id\":null,\"contact_id\":97,\"lead_id\":null}]} {\"correlation_id\":\"87d35b30-46fd-4cbe-815e-3c7fc0873c55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:14] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"87d35b30-46fd-4cbe-815e-3c7fc0873c55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:14] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"87d35b30-46fd-4cbe-815e-3c7fc0873c55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:14] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"87d35b30-46fd-4cbe-815e-3c7fc0873c55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:14] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"87d35b30-46fd-4cbe-815e-3c7fc0873c55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:14] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612558,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"87d35b30-46fd-4cbe-815e-3c7fc0873c55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:14] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinsoncrusoe@test.com\"} {\"correlation_id\":\"87d35b30-46fd-4cbe-815e-3c7fc0873c55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:14] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612558,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"87d35b30-46fd-4cbe-815e-3c7fc0873c55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:14] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612558} {\"correlation_id\":\"87d35b30-46fd-4cbe-815e-3c7fc0873c55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:14] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612558,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"87d35b30-46fd-4cbe-815e-3c7fc0873c55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:14] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612558,\"remote_search\":true,\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34} {\"correlation_id\":\"87d35b30-46fd-4cbe-815e-3c7fc0873c55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:15] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612557,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34}} {\"correlation_id\":\"f4441c9e-1575-406a-9087-739d00f7051a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:15] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612557} {\"correlation_id\":\"f4441c9e-1575-406a-9087-739d00f7051a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:15] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612557,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"f4441c9e-1575-406a-9087-739d00f7051a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:15] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612557,\"participants\":[{\"id\":999772,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999773,\"user_id\":null,\"contact_id\":97,\"lead_id\":null}]} {\"correlation_id\":\"f4441c9e-1575-406a-9087-739d00f7051a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:16] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"f4441c9e-1575-406a-9087-739d00f7051a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:16] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"f4441c9e-1575-406a-9087-739d00f7051a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:16] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"f4441c9e-1575-406a-9087-739d00f7051a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:16] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"f4441c9e-1575-406a-9087-739d00f7051a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:16] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612557,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"f4441c9e-1575-406a-9087-739d00f7051a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:16] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinsoncrusoe@test.com\"} {\"correlation_id\":\"f4441c9e-1575-406a-9087-739d00f7051a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:16] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612557,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"f4441c9e-1575-406a-9087-739d00f7051a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:16] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612557} {\"correlation_id\":\"f4441c9e-1575-406a-9087-739d00f7051a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:16] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612557,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"f4441c9e-1575-406a-9087-739d00f7051a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:16] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612557,\"remote_search\":true,\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34} {\"correlation_id\":\"f4441c9e-1575-406a-9087-739d00f7051a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:17] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612556,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34}} {\"correlation_id\":\"0c63e1d6-a318-43c2-8cc4-a2e00c5260e3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:17] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612556} {\"correlation_id\":\"0c63e1d6-a318-43c2-8cc4-a2e00c5260e3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:17] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612556,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"0c63e1d6-a318-43c2-8cc4-a2e00c5260e3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:17] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612556,\"participants\":[{\"id\":999770,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999771,\"user_id\":null,\"contact_id\":97,\"lead_id\":null}]} {\"correlation_id\":\"0c63e1d6-a318-43c2-8cc4-a2e00c5260e3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:17] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"0c63e1d6-a318-43c2-8cc4-a2e00c5260e3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:17] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"0c63e1d6-a318-43c2-8cc4-a2e00c5260e3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:17] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"0c63e1d6-a318-43c2-8cc4-a2e00c5260e3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:17] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"0c63e1d6-a318-43c2-8cc4-a2e00c5260e3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:17] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612556,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"0c63e1d6-a318-43c2-8cc4-a2e00c5260e3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:17] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinsoncrusoe@test.com\"} {\"correlation_id\":\"0c63e1d6-a318-43c2-8cc4-a2e00c5260e3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:17] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612556,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"0c63e1d6-a318-43c2-8cc4-a2e00c5260e3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:17] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612556} {\"correlation_id\":\"0c63e1d6-a318-43c2-8cc4-a2e00c5260e3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:17] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612556,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"0c63e1d6-a318-43c2-8cc4-a2e00c5260e3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:17] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612556,\"remote_search\":true,\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34} {\"correlation_id\":\"0c63e1d6-a318-43c2-8cc4-a2e00c5260e3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:17] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612555,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34}} {\"correlation_id\":\"3268196e-0a93-4fd3-a61b-5dfcc3e560a8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:18] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612555} {\"correlation_id\":\"3268196e-0a93-4fd3-a61b-5dfcc3e560a8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:18] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612555,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"3268196e-0a93-4fd3-a61b-5dfcc3e560a8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:18] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612555,\"participants\":[{\"id\":999768,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999769,\"user_id\":null,\"contact_id\":97,\"lead_id\":null}]} {\"correlation_id\":\"3268196e-0a93-4fd3-a61b-5dfcc3e560a8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:18] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"3268196e-0a93-4fd3-a61b-5dfcc3e560a8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:18] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"3268196e-0a93-4fd3-a61b-5dfcc3e560a8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:18] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"3268196e-0a93-4fd3-a61b-5dfcc3e560a8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:18] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"3268196e-0a93-4fd3-a61b-5dfcc3e560a8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:18] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612555,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"3268196e-0a93-4fd3-a61b-5dfcc3e560a8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:18] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinsoncrusoe@test.com\"} {\"correlation_id\":\"3268196e-0a93-4fd3-a61b-5dfcc3e560a8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:18] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612555,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"3268196e-0a93-4fd3-a61b-5dfcc3e560a8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:18] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612555} {\"correlation_id\":\"3268196e-0a93-4fd3-a61b-5dfcc3e560a8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:18] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612555,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"3268196e-0a93-4fd3-a61b-5dfcc3e560a8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612555,\"remote_search\":true,\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34} {\"correlation_id\":\"3268196e-0a93-4fd3-a61b-5dfcc3e560a8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [ EsUpdateProcessManager ] Finished updating entities in ES {\"worker\":\"\",\"peak_memory\":\"99.73 MB\",\"elapsed_seconds\":11.49,\"update_target\":\"activities\",\"should_iterate_again\":false} {\"correlation_id\":\"4ad05333-9afb-492e-9f0f-b2909ac45b32\",\"trace_id\":\"3d8feb24-b173-4158-b0a4-4cf33af85066\"}\n[2026-05-11 10:17:19] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612554,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34}} {\"correlation_id\":\"09a1bea2-5b92-4a89-8617-bc5809db48d1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612554} {\"correlation_id\":\"09a1bea2-5b92-4a89-8617-bc5809db48d1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612554,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"09a1bea2-5b92-4a89-8617-bc5809db48d1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612554,\"participants\":[{\"id\":999766,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999767,\"user_id\":null,\"contact_id\":97,\"lead_id\":null}]} {\"correlation_id\":\"09a1bea2-5b92-4a89-8617-bc5809db48d1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"09a1bea2-5b92-4a89-8617-bc5809db48d1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"09a1bea2-5b92-4a89-8617-bc5809db48d1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"09a1bea2-5b92-4a89-8617-bc5809db48d1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"09a1bea2-5b92-4a89-8617-bc5809db48d1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612554,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"09a1bea2-5b92-4a89-8617-bc5809db48d1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinsoncrusoe@test.com\"} {\"correlation_id\":\"09a1bea2-5b92-4a89-8617-bc5809db48d1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612554,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"09a1bea2-5b92-4a89-8617-bc5809db48d1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612554} {\"correlation_id\":\"09a1bea2-5b92-4a89-8617-bc5809db48d1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612554,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"09a1bea2-5b92-4a89-8617-bc5809db48d1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612554,\"remote_search\":true,\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34} {\"correlation_id\":\"09a1bea2-5b92-4a89-8617-bc5809db48d1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612553,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34}} {\"correlation_id\":\"40b197d4-a099-4e5a-9b85-7d5e01a97d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612553} {\"correlation_id\":\"40b197d4-a099-4e5a-9b85-7d5e01a97d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612553,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"40b197d4-a099-4e5a-9b85-7d5e01a97d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612553,\"participants\":[{\"id\":999764,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999765,\"user_id\":null,\"contact_id\":97,\"lead_id\":null}]} {\"correlation_id\":\"40b197d4-a099-4e5a-9b85-7d5e01a97d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"40b197d4-a099-4e5a-9b85-7d5e01a97d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"40b197d4-a099-4e5a-9b85-7d5e01a97d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"40b197d4-a099-4e5a-9b85-7d5e01a97d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"40b197d4-a099-4e5a-9b85-7d5e01a97d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612553,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"40b197d4-a099-4e5a-9b85-7d5e01a97d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinsoncrusoe@test.com\"} {\"correlation_id\":\"40b197d4-a099-4e5a-9b85-7d5e01a97d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612553,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"40b197d4-a099-4e5a-9b85-7d5e01a97d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612553} {\"correlation_id\":\"40b197d4-a099-4e5a-9b85-7d5e01a97d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612553,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"40b197d4-a099-4e5a-9b85-7d5e01a97d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612553,\"remote_search\":true,\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34} {\"correlation_id\":\"40b197d4-a099-4e5a-9b85-7d5e01a97d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612552,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34}} {\"correlation_id\":\"6548c611-b94a-40c9-8a0e-d3c24ba47072\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612552} {\"correlation_id\":\"6548c611-b94a-40c9-8a0e-d3c24ba47072\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612552,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"6548c611-b94a-40c9-8a0e-d3c24ba47072\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612552,\"participants\":[{\"id\":999762,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999763,\"user_id\":null,\"contact_id\":97,\"lead_id\":null}]} {\"correlation_id\":\"6548c611-b94a-40c9-8a0e-d3c24ba47072\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"6548c611-b94a-40c9-8a0e-d3c24ba47072\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"6548c611-b94a-40c9-8a0e-d3c24ba47072\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6548c611-b94a-40c9-8a0e-d3c24ba47072\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"6548c611-b94a-40c9-8a0e-d3c24ba47072\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612552,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"6548c611-b94a-40c9-8a0e-d3c24ba47072\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinsoncrusoe@test.com\"} {\"correlation_id\":\"6548c611-b94a-40c9-8a0e-d3c24ba47072\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612552,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"6548c611-b94a-40c9-8a0e-d3c24ba47072\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612552} {\"correlation_id\":\"6548c611-b94a-40c9-8a0e-d3c24ba47072\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612552,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"6548c611-b94a-40c9-8a0e-d3c24ba47072\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612552,\"remote_search\":true,\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34} {\"correlation_id\":\"6548c611-b94a-40c9-8a0e-d3c24ba47072\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612551,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34}} {\"correlation_id\":\"4cce51ee-846b-43b2-a0cd-d83dc5eff920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612551} {\"correlation_id\":\"4cce51ee-846b-43b2-a0cd-d83dc5eff920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612551,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"4cce51ee-846b-43b2-a0cd-d83dc5eff920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612551,\"participants\":[{\"id\":999760,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999761,\"user_id\":null,\"contact_id\":97,\"lead_id\":null}]} {\"correlation_id\":\"4cce51ee-846b-43b2-a0cd-d83dc5eff920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4cce51ee-846b-43b2-a0cd-d83dc5eff920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4cce51ee-846b-43b2-a0cd-d83dc5eff920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"4cce51ee-846b-43b2-a0cd-d83dc5eff920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"4cce51ee-846b-43b2-a0cd-d83dc5eff920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612551,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"4cce51ee-846b-43b2-a0cd-d83dc5eff920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinsoncrusoe@test.com\"} {\"correlation_id\":\"4cce51ee-846b-43b2-a0cd-d83dc5eff920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612551,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"4cce51ee-846b-43b2-a0cd-d83dc5eff920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612551} {\"correlation_id\":\"4cce51ee-846b-43b2-a0cd-d83dc5eff920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612551,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"4cce51ee-846b-43b2-a0cd-d83dc5eff920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612551,\"remote_search\":true,\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34} {\"correlation_id\":\"4cce51ee-846b-43b2-a0cd-d83dc5eff920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612550,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34}} {\"correlation_id\":\"b0e6efce-5447-4d7d-be32-a4dfafa64fdc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612550} {\"correlation_id\":\"b0e6efce-5447-4d7d-be32-a4dfafa64fdc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612550,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"b0e6efce-5447-4d7d-be32-a4dfafa64fdc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612550,\"participants\":[{\"id\":999758,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999759,\"user_id\":null,\"contact_id\":97,\"lead_id\":null}]} {\"correlation_id\":\"b0e6efce-5447-4d7d-be32-a4dfafa64fdc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b0e6efce-5447-4d7d-be32-a4dfafa64fdc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b0e6efce-5447-4d7d-be32-a4dfafa64fdc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"b0e6efce-5447-4d7d-be32-a4dfafa64fdc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"b0e6efce-5447-4d7d-be32-a4dfafa64fdc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612550,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"b0e6efce-5447-4d7d-be32-a4dfafa64fdc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinsoncrusoe@test.com\"} {\"correlation_id\":\"b0e6efce-5447-4d7d-be32-a4dfafa64fdc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612550,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"b0e6efce-5447-4d7d-be32-a4dfafa64fdc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612550} {\"correlation_id\":\"b0e6efce-5447-4d7d-be32-a4dfafa64fdc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612550,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"b0e6efce-5447-4d7d-be32-a4dfafa64fdc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612550,\"remote_search\":true,\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34} {\"correlation_id\":\"b0e6efce-5447-4d7d-be32-a4dfafa64fdc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612549,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34}} {\"correlation_id\":\"e8c5b540-3796-4bed-b52c-3f7a6b7586aa\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612549} {\"correlation_id\":\"e8c5b540-3796-4bed-b52c-3f7a6b7586aa\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612549,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"e8c5b540-3796-4bed-b52c-3f7a6b7586aa\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612549,\"participants\":[{\"id\":999756,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999757,\"user_id\":null,\"contact_id\":97,\"lead_id\":null}]} {\"correlation_id\":\"e8c5b540-3796-4bed-b52c-3f7a6b7586aa\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"e8c5b540-3796-4bed-b52c-3f7a6b7586aa\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"e8c5b540-3796-4bed-b52c-3f7a6b7586aa\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"e8c5b540-3796-4bed-b52c-3f7a6b7586aa\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"e8c5b540-3796-4bed-b52c-3f7a6b7586aa\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612549,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"e8c5b540-3796-4bed-b52c-3f7a6b7586aa\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinsoncrusoe@test.com\"} {\"correlation_id\":\"e8c5b540-3796-4bed-b52c-3f7a6b7586aa\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612549,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"e8c5b540-3796-4bed-b52c-3f7a6b7586aa\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612549} {\"correlation_id\":\"e8c5b540-3796-4bed-b52c-3f7a6b7586aa\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612549,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"e8c5b540-3796-4bed-b52c-3f7a6b7586aa\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612549,\"remote_search\":true,\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34} {\"correlation_id\":\"e8c5b540-3796-4bed-b52c-3f7a6b7586aa\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612365,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"e5125373-9a81-49ac-ab11-5aebfe6aea74\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612365} {\"correlation_id\":\"e5125373-9a81-49ac-ab11-5aebfe6aea74\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612365,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"e5125373-9a81-49ac-ab11-5aebfe6aea74\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612365,\"participants\":[{\"id\":999563,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999564,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"e5125373-9a81-49ac-ab11-5aebfe6aea74\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"e5125373-9a81-49ac-ab11-5aebfe6aea74\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"e5125373-9a81-49ac-ab11-5aebfe6aea74\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"e5125373-9a81-49ac-ab11-5aebfe6aea74\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"e5125373-9a81-49ac-ab11-5aebfe6aea74\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"e5125373-9a81-49ac-ab11-5aebfe6aea74\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612365,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"e5125373-9a81-49ac-ab11-5aebfe6aea74\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612365,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"e5125373-9a81-49ac-ab11-5aebfe6aea74\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612365} {\"correlation_id\":\"e5125373-9a81-49ac-ab11-5aebfe6aea74\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612365,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"e5125373-9a81-49ac-ab11-5aebfe6aea74\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612365,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"e5125373-9a81-49ac-ab11-5aebfe6aea74\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:22] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612360,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"611796ed-b766-420d-a544-4fdb1123b4f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:22] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612360} {\"correlation_id\":\"611796ed-b766-420d-a544-4fdb1123b4f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:22] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612360,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"611796ed-b766-420d-a544-4fdb1123b4f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:22] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612360,\"participants\":[{\"id\":999552,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999553,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999565,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"611796ed-b766-420d-a544-4fdb1123b4f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:22] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"611796ed-b766-420d-a544-4fdb1123b4f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:22] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"611796ed-b766-420d-a544-4fdb1123b4f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:22] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"611796ed-b766-420d-a544-4fdb1123b4f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:22] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"611796ed-b766-420d-a544-4fdb1123b4f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:22] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"611796ed-b766-420d-a544-4fdb1123b4f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:22] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612360,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"611796ed-b766-420d-a544-4fdb1123b4f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:22] local.WARNING: [Hubspot] No retry-after header or policy name found, using default {\"exception_class\":\"SevenShores\\\\Hubspot\\\\Exceptions\\\\BadRequest\"} {\"correlation_id\":\"611796ed-b766-420d-a544-4fdb1123b4f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:22] local.WARNING: [Hubspot] Received 429 from API {\"team_id\":2,\"config_id\":2,\"retry_after\":10,\"policy\":null,\"reason\":\"Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response:\n{\\\"status\\\":\\\"error\\\",\\\"message\\\":\\\"You have reached your secondly limit.\\\",\\\"errorType\\\":\\\"RATE_LIMIT\\\",\\\"correlationId\\\":\\\"019e168a-9 (truncated...)\n\"} {\"correlation_id\":\"611796ed-b766-420d-a544-4fdb1123b4f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:22] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":12} {\"correlation_id\":\"611796ed-b766-420d-a544-4fdb1123b4f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:23] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612340,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"f69192c9-9ba8-48e0-b614-996bf3dcc7d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:23] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612340} {\"correlation_id\":\"f69192c9-9ba8-48e0-b614-996bf3dcc7d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:23] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612340,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"f69192c9-9ba8-48e0-b614-996bf3dcc7d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:23] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612340,\"participants\":[{\"id\":999516,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999517,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999518,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999519,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"f69192c9-9ba8-48e0-b614-996bf3dcc7d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:23] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"f69192c9-9ba8-48e0-b614-996bf3dcc7d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:23] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"f69192c9-9ba8-48e0-b614-996bf3dcc7d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:23] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"f69192c9-9ba8-48e0-b614-996bf3dcc7d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:23] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"f69192c9-9ba8-48e0-b614-996bf3dcc7d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:23] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"f69192c9-9ba8-48e0-b614-996bf3dcc7d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:23] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612340,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"f69192c9-9ba8-48e0-b614-996bf3dcc7d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:23] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"f69192c9-9ba8-48e0-b614-996bf3dcc7d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:23] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612339,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"6522d428-c400-448c-9130-a06133b21471\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:23] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612339} {\"correlation_id\":\"6522d428-c400-448c-9130-a06133b21471\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612339,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"6522d428-c400-448c-9130-a06133b21471\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612339,\"participants\":[{\"id\":999514,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999515,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999540,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"6522d428-c400-448c-9130-a06133b21471\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"6522d428-c400-448c-9130-a06133b21471\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"6522d428-c400-448c-9130-a06133b21471\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6522d428-c400-448c-9130-a06133b21471\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"6522d428-c400-448c-9130-a06133b21471\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"6522d428-c400-448c-9130-a06133b21471\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612339,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"6522d428-c400-448c-9130-a06133b21471\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"6522d428-c400-448c-9130-a06133b21471\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612336,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"0588c797-4ae0-4d7b-b3ee-9706e7ef39df\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612336} {\"correlation_id\":\"0588c797-4ae0-4d7b-b3ee-9706e7ef39df\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612336,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"0588c797-4ae0-4d7b-b3ee-9706e7ef39df\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612336,\"participants\":[{\"id\":999508,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999509,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999512,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999513,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"0588c797-4ae0-4d7b-b3ee-9706e7ef39df\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"0588c797-4ae0-4d7b-b3ee-9706e7ef39df\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"0588c797-4ae0-4d7b-b3ee-9706e7ef39df\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"0588c797-4ae0-4d7b-b3ee-9706e7ef39df\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"0588c797-4ae0-4d7b-b3ee-9706e7ef39df\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"0588c797-4ae0-4d7b-b3ee-9706e7ef39df\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612336,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"0588c797-4ae0-4d7b-b3ee-9706e7ef39df\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":15} {\"correlation_id\":\"0588c797-4ae0-4d7b-b3ee-9706e7ef39df\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612183,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"946c4e96-6983-445b-a842-b212439024fd\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612183} {\"correlation_id\":\"946c4e96-6983-445b-a842-b212439024fd\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612183,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"946c4e96-6983-445b-a842-b212439024fd\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612183,\"participants\":[{\"id\":999227,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":999228,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"946c4e96-6983-445b-a842-b212439024fd\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"946c4e96-6983-445b-a842-b212439024fd\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"946c4e96-6983-445b-a842-b212439024fd\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"946c4e96-6983-445b-a842-b212439024fd\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"946c4e96-6983-445b-a842-b212439024fd\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"946c4e96-6983-445b-a842-b212439024fd\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612183,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"946c4e96-6983-445b-a842-b212439024fd\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612183,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"946c4e96-6983-445b-a842-b212439024fd\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612183} {\"correlation_id\":\"946c4e96-6983-445b-a842-b212439024fd\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612183,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"946c4e96-6983-445b-a842-b212439024fd\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612183,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"946c4e96-6983-445b-a842-b212439024fd\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612182,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"f5eaabe1-ed2b-4779-8907-9a7cb181c90e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612182} {\"correlation_id\":\"f5eaabe1-ed2b-4779-8907-9a7cb181c90e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612182,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"f5eaabe1-ed2b-4779-8907-9a7cb181c90e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612182,\"participants\":[{\"id\":999225,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":999226,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"f5eaabe1-ed2b-4779-8907-9a7cb181c90e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"f5eaabe1-ed2b-4779-8907-9a7cb181c90e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"f5eaabe1-ed2b-4779-8907-9a7cb181c90e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"f5eaabe1-ed2b-4779-8907-9a7cb181c90e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"f5eaabe1-ed2b-4779-8907-9a7cb181c90e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"f5eaabe1-ed2b-4779-8907-9a7cb181c90e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612182,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"f5eaabe1-ed2b-4779-8907-9a7cb181c90e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612182,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"f5eaabe1-ed2b-4779-8907-9a7cb181c90e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612182} {\"correlation_id\":\"f5eaabe1-ed2b-4779-8907-9a7cb181c90e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612182,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"f5eaabe1-ed2b-4779-8907-9a7cb181c90e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612182,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"f5eaabe1-ed2b-4779-8907-9a7cb181c90e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"86d5bdfe-cc94-41f2-94ba-422242e4e1f5\",\"trace_id\":\"659a90d1-e357-4e8c-a391-979e687c5ae4\"}\n[2026-05-11 10:17:25] local.INFO: [ EsUpdateProcessManager ] Finished updating entities in ES {\"worker\":\"\",\"peak_memory\":\"99.73 MB\",\"elapsed_seconds\":1.26,\"update_target\":\"activities\",\"should_iterate_again\":false} {\"correlation_id\":\"4ad05333-9afb-492e-9f0f-b2909ac45b32\",\"trace_id\":\"3d8feb24-b173-4158-b0a4-4cf33af85066\"}\n[2026-05-11 10:17:25] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612181,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"d2216c54-0324-4668-a561-66c972bd24b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612181} {\"correlation_id\":\"d2216c54-0324-4668-a561-66c972bd24b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612181,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"d2216c54-0324-4668-a561-66c972bd24b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612181,\"participants\":[{\"id\":999223,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":999224,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"d2216c54-0324-4668-a561-66c972bd24b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"d2216c54-0324-4668-a561-66c972bd24b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"d2216c54-0324-4668-a561-66c972bd24b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"d2216c54-0324-4668-a561-66c972bd24b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"d2216c54-0324-4668-a561-66c972bd24b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"d2216c54-0324-4668-a561-66c972bd24b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"86d5bdfe-cc94-41f2-94ba-422242e4e1f5\",\"trace_id\":\"659a90d1-e357-4e8c-a391-979e687c5ae4\"}\n[2026-05-11 10:17:25] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612181,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"d2216c54-0324-4668-a561-66c972bd24b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612181,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"d2216c54-0324-4668-a561-66c972bd24b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612181} {\"correlation_id\":\"d2216c54-0324-4668-a561-66c972bd24b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612181,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"d2216c54-0324-4668-a561-66c972bd24b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612181,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"d2216c54-0324-4668-a561-66c972bd24b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612180,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"f8c127c2-60ef-47b1-b0e2-5adb2b6d7349\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612180} {\"correlation_id\":\"f8c127c2-60ef-47b1-b0e2-5adb2b6d7349\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612180,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"f8c127c2-60ef-47b1-b0e2-5adb2b6d7349\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612180,\"participants\":[{\"id\":999221,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":999222,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"f8c127c2-60ef-47b1-b0e2-5adb2b6d7349\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"f8c127c2-60ef-47b1-b0e2-5adb2b6d7349\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"f8c127c2-60ef-47b1-b0e2-5adb2b6d7349\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"f8c127c2-60ef-47b1-b0e2-5adb2b6d7349\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"f8c127c2-60ef-47b1-b0e2-5adb2b6d7349\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"f8c127c2-60ef-47b1-b0e2-5adb2b6d7349\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612180,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"f8c127c2-60ef-47b1-b0e2-5adb2b6d7349\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612180,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"f8c127c2-60ef-47b1-b0e2-5adb2b6d7349\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612180} {\"correlation_id\":\"f8c127c2-60ef-47b1-b0e2-5adb2b6d7349\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612180,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"f8c127c2-60ef-47b1-b0e2-5adb2b6d7349\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612180,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"f8c127c2-60ef-47b1-b0e2-5adb2b6d7349\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611455,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"0869934c-f4d0-46a1-8387-f2393c5bce93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611455} {\"correlation_id\":\"0869934c-f4d0-46a1-8387-f2393c5bce93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611455,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"0869934c-f4d0-46a1-8387-f2393c5bce93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611455,\"participants\":[{\"id\":997961,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997962,\"user_id\":1460,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"0869934c-f4d0-46a1-8387-f2393c5bce93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"0869934c-f4d0-46a1-8387-f2393c5bce93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"0869934c-f4d0-46a1-8387-f2393c5bce93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"0869934c-f4d0-46a1-8387-f2393c5bce93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"0869934c-f4d0-46a1-8387-f2393c5bce93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"0869934c-f4d0-46a1-8387-f2393c5bce93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"support@staging.jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/support%40staging.jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"correlation_id\":\"0869934c-f4d0-46a1-8387-f2393c5bce93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"0869934c-f4d0-46a1-8387-f2393c5bce93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"0869934c-f4d0-46a1-8387-f2393c5bce93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611451,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"4e3d1181-634e-4ea2-8ac6-7da2a722c455\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611451} {\"correlation_id\":\"4e3d1181-634e-4ea2-8ac6-7da2a722c455\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611451,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"4e3d1181-634e-4ea2-8ac6-7da2a722c455\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611451,\"participants\":[{\"id\":997955,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997956,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"4e3d1181-634e-4ea2-8ac6-7da2a722c455\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4e3d1181-634e-4ea2-8ac6-7da2a722c455\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4e3d1181-634e-4ea2-8ac6-7da2a722c455\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"4e3d1181-634e-4ea2-8ac6-7da2a722c455\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"4e3d1181-634e-4ea2-8ac6-7da2a722c455\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"4e3d1181-634e-4ea2-8ac6-7da2a722c455\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"support@staging.jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/support%40staging.jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"correlation_id\":\"4e3d1181-634e-4ea2-8ac6-7da2a722c455\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"4e3d1181-634e-4ea2-8ac6-7da2a722c455\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"4e3d1181-634e-4ea2-8ac6-7da2a722c455\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611087,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"bd88fcdb-25fc-4e20-bec3-36897d7c6d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611087} {\"correlation_id\":\"bd88fcdb-25fc-4e20-bec3-36897d7c6d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611087,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"bd88fcdb-25fc-4e20-bec3-36897d7c6d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611087,\"participants\":[{\"id\":997368,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997369,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"bd88fcdb-25fc-4e20-bec3-36897d7c6d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"bd88fcdb-25fc-4e20-bec3-36897d7c6d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"bd88fcdb-25fc-4e20-bec3-36897d7c6d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"bd88fcdb-25fc-4e20-bec3-36897d7c6d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"bd88fcdb-25fc-4e20-bec3-36897d7c6d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"bd88fcdb-25fc-4e20-bec3-36897d7c6d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"bd88fcdb-25fc-4e20-bec3-36897d7c6d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":10} {\"correlation_id\":\"bd88fcdb-25fc-4e20-bec3-36897d7c6d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611076,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"c1d5bb08-3fac-4938-926a-3e672915d6c3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611076} {\"correlation_id\":\"c1d5bb08-3fac-4938-926a-3e672915d6c3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611076,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"c1d5bb08-3fac-4938-926a-3e672915d6c3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611076,\"participants\":[{\"id\":997346,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997347,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"c1d5bb08-3fac-4938-926a-3e672915d6c3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"c1d5bb08-3fac-4938-926a-3e672915d6c3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"c1d5bb08-3fac-4938-926a-3e672915d6c3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"c1d5bb08-3fac-4938-926a-3e672915d6c3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"c1d5bb08-3fac-4938-926a-3e672915d6c3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"c1d5bb08-3fac-4938-926a-3e672915d6c3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"c1d5bb08-3fac-4938-926a-3e672915d6c3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":10} {\"correlation_id\":\"c1d5bb08-3fac-4938-926a-3e672915d6c3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610935,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"c1161db6-2192-487f-94d9-fb763ee00ea9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610935} {\"correlation_id\":\"c1161db6-2192-487f-94d9-fb763ee00ea9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610935,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"c1161db6-2192-487f-94d9-fb763ee00ea9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610935,\"participants\":[{\"id\":997141,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997142,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"c1161db6-2192-487f-94d9-fb763ee00ea9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"c1161db6-2192-487f-94d9-fb763ee00ea9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"c1161db6-2192-487f-94d9-fb763ee00ea9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"c1161db6-2192-487f-94d9-fb763ee00ea9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"c1161db6-2192-487f-94d9-fb763ee00ea9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"c1161db6-2192-487f-94d9-fb763ee00ea9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"c1161db6-2192-487f-94d9-fb763ee00ea9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"c1161db6-2192-487f-94d9-fb763ee00ea9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610915,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"bd974d1f-98c3-43ec-a0ee-c373b13e5a55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610915} {\"correlation_id\":\"bd974d1f-98c3-43ec-a0ee-c373b13e5a55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610915,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"bd974d1f-98c3-43ec-a0ee-c373b13e5a55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610915,\"participants\":[{\"id\":997104,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997105,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"bd974d1f-98c3-43ec-a0ee-c373b13e5a55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"bd974d1f-98c3-43ec-a0ee-c373b13e5a55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"bd974d1f-98c3-43ec-a0ee-c373b13e5a55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"bd974d1f-98c3-43ec-a0ee-c373b13e5a55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"bd974d1f-98c3-43ec-a0ee-c373b13e5a55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"bd974d1f-98c3-43ec-a0ee-c373b13e5a55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"bd974d1f-98c3-43ec-a0ee-c373b13e5a55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":13} {\"correlation_id\":\"bd974d1f-98c3-43ec-a0ee-c373b13e5a55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610900,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"6b6b45e9-7387-4b73-a6c1-1302a6e959cc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610900} {\"correlation_id\":\"6b6b45e9-7387-4b73-a6c1-1302a6e959cc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610900,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"6b6b45e9-7387-4b73-a6c1-1302a6e959cc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610900,\"participants\":[{\"id\":997081,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997082,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"6b6b45e9-7387-4b73-a6c1-1302a6e959cc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"6b6b45e9-7387-4b73-a6c1-1302a6e959cc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"6b6b45e9-7387-4b73-a6c1-1302a6e959cc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6b6b45e9-7387-4b73-a6c1-1302a6e959cc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"6b6b45e9-7387-4b73-a6c1-1302a6e959cc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"6b6b45e9-7387-4b73-a6c1-1302a6e959cc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"6b6b45e9-7387-4b73-a6c1-1302a6e959cc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":10} {\"correlation_id\":\"6b6b45e9-7387-4b73-a6c1-1302a6e959cc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610885,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"3d3fbb4c-6268-4e40-bf22-931be4baeb1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610885} {\"correlation_id\":\"3d3fbb4c-6268-4e40-bf22-931be4baeb1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610885,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"3d3fbb4c-6268-4e40-bf22-931be4baeb1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610885,\"participants\":[{\"id\":997051,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997052,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"3d3fbb4c-6268-4e40-bf22-931be4baeb1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"3d3fbb4c-6268-4e40-bf22-931be4baeb1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"3d3fbb4c-6268-4e40-bf22-931be4baeb1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"3d3fbb4c-6268-4e40-bf22-931be4baeb1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"3d3fbb4c-6268-4e40-bf22-931be4baeb1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"3d3fbb4c-6268-4e40-bf22-931be4baeb1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"3d3fbb4c-6268-4e40-bf22-931be4baeb1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"3d3fbb4c-6268-4e40-bf22-931be4baeb1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610878,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"75bdd542-1e62-4704-861a-810a631074bf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610878} {\"correlation_id\":\"75bdd542-1e62-4704-861a-810a631074bf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610878,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"75bdd542-1e62-4704-861a-810a631074bf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610878,\"participants\":[{\"id\":997035,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997036,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"75bdd542-1e62-4704-861a-810a631074bf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"75bdd542-1e62-4704-861a-810a631074bf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"75bdd542-1e62-4704-861a-810a631074bf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"75bdd542-1e62-4704-861a-810a631074bf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"75bdd542-1e62-4704-861a-810a631074bf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"75bdd542-1e62-4704-861a-810a631074bf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"75bdd542-1e62-4704-861a-810a631074bf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"75bdd542-1e62-4704-861a-810a631074bf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610874,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"923e5701-fa97-4252-a235-5cfe1a50c951\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610874} {\"correlation_id\":\"923e5701-fa97-4252-a235-5cfe1a50c951\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610874,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"923e5701-fa97-4252-a235-5cfe1a50c951\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610874,\"participants\":[{\"id\":997025,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997026,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"923e5701-fa97-4252-a235-5cfe1a50c951\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"923e5701-fa97-4252-a235-5cfe1a50c951\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"923e5701-fa97-4252-a235-5cfe1a50c951\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"923e5701-fa97-4252-a235-5cfe1a50c951\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"923e5701-fa97-4252-a235-5cfe1a50c951\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"923e5701-fa97-4252-a235-5cfe1a50c951\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"923e5701-fa97-4252-a235-5cfe1a50c951\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":15} {\"correlation_id\":\"923e5701-fa97-4252-a235-5cfe1a50c951\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:30] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610867,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"afecdc02-a4b8-431a-baee-e5f104160539\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:30] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610867} {\"correlation_id\":\"afecdc02-a4b8-431a-baee-e5f104160539\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:30] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610867,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"afecdc02-a4b8-431a-baee-e5f104160539\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:30] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610867,\"participants\":[{\"id\":997011,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997012,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"afecdc02-a4b8-431a-baee-e5f104160539\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:30] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"afecdc02-a4b8-431a-baee-e5f104160539\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:30] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"afecdc02-a4b8-431a-baee-e5f104160539\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:30] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"afecdc02-a4b8-431a-baee-e5f104160539\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:30] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"afecdc02-a4b8-431a-baee-e5f104160539\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"afecdc02-a4b8-431a-baee-e5f104160539\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"afecdc02-a4b8-431a-baee-e5f104160539\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"afecdc02-a4b8-431a-baee-e5f104160539\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610764,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"30a67f60-f844-4758-bc2c-79a6b1ec958a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610764} {\"correlation_id\":\"30a67f60-f844-4758-bc2c-79a6b1ec958a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610764,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"30a67f60-f844-4758-bc2c-79a6b1ec958a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610764,\"participants\":[{\"id\":996951,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996952,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"30a67f60-f844-4758-bc2c-79a6b1ec958a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"30a67f60-f844-4758-bc2c-79a6b1ec958a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"30a67f60-f844-4758-bc2c-79a6b1ec958a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"30a67f60-f844-4758-bc2c-79a6b1ec958a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"30a67f60-f844-4758-bc2c-79a6b1ec958a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"30a67f60-f844-4758-bc2c-79a6b1ec958a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"30a67f60-f844-4758-bc2c-79a6b1ec958a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":10} {\"correlation_id\":\"30a67f60-f844-4758-bc2c-79a6b1ec958a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610617,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"2989f086-0b73-4b12-b24c-8665376dcf18\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610617} {\"correlation_id\":\"2989f086-0b73-4b12-b24c-8665376dcf18\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610617,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"2989f086-0b73-4b12-b24c-8665376dcf18\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610617,\"participants\":[{\"id\":996641,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996642,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"2989f086-0b73-4b12-b24c-8665376dcf18\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"2989f086-0b73-4b12-b24c-8665376dcf18\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"2989f086-0b73-4b12-b24c-8665376dcf18\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"2989f086-0b73-4b12-b24c-8665376dcf18\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"2989f086-0b73-4b12-b24c-8665376dcf18\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"2989f086-0b73-4b12-b24c-8665376dcf18\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"2989f086-0b73-4b12-b24c-8665376dcf18\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"2989f086-0b73-4b12-b24c-8665376dcf18\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [ EsUpdateProcessManager ] Finished updating entities in ES {\"worker\":\"\",\"peak_memory\":\"99.73 MB\",\"elapsed_seconds\":0.9,\"update_target\":\"activities\",\"should_iterate_again\":false} {\"correlation_id\":\"4ad05333-9afb-492e-9f0f-b2909ac45b32\",\"trace_id\":\"3d8feb24-b173-4158-b0a4-4cf33af85066\"}\n[2026-05-11 10:17:31] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610539,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"0c19e519-0adf-4903-a45d-44559f23151f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610539} {\"correlation_id\":\"0c19e519-0adf-4903-a45d-44559f23151f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610539,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"0c19e519-0adf-4903-a45d-44559f23151f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610539,\"participants\":[{\"id\":996485,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996486,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"0c19e519-0adf-4903-a45d-44559f23151f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"0c19e519-0adf-4903-a45d-44559f23151f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"0c19e519-0adf-4903-a45d-44559f23151f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"0c19e519-0adf-4903-a45d-44559f23151f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"0c19e519-0adf-4903-a45d-44559f23151f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"0c19e519-0adf-4903-a45d-44559f23151f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"0c19e519-0adf-4903-a45d-44559f23151f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":10} {\"correlation_id\":\"0c19e519-0adf-4903-a45d-44559f23151f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610528,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"fc1002b7-ac5b-4080-b6fa-497070177a88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610528} {\"correlation_id\":\"fc1002b7-ac5b-4080-b6fa-497070177a88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610528,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"fc1002b7-ac5b-4080-b6fa-497070177a88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610528,\"participants\":[{\"id\":996463,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996464,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"fc1002b7-ac5b-4080-b6fa-497070177a88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"fc1002b7-ac5b-4080-b6fa-497070177a88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"fc1002b7-ac5b-4080-b6fa-497070177a88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"fc1002b7-ac5b-4080-b6fa-497070177a88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"fc1002b7-ac5b-4080-b6fa-497070177a88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"fc1002b7-ac5b-4080-b6fa-497070177a88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"fc1002b7-ac5b-4080-b6fa-497070177a88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"fc1002b7-ac5b-4080-b6fa-497070177a88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610506,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"738402b4-5306-4346-9286-7b1fb94db69f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610506} {\"correlation_id\":\"738402b4-5306-4346-9286-7b1fb94db69f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610506,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"738402b4-5306-4346-9286-7b1fb94db69f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610506,\"participants\":[{\"id\":996419,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996420,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"738402b4-5306-4346-9286-7b1fb94db69f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"738402b4-5306-4346-9286-7b1fb94db69f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"738402b4-5306-4346-9286-7b1fb94db69f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"738402b4-5306-4346-9286-7b1fb94db69f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"738402b4-5306-4346-9286-7b1fb94db69f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"738402b4-5306-4346-9286-7b1fb94db69f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"738402b4-5306-4346-9286-7b1fb94db69f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":13} {\"correlation_id\":\"738402b4-5306-4346-9286-7b1fb94db69f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610497,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"2356bf77-077c-400e-ac58-cebd0719ff80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610497} {\"correlation_id\":\"2356bf77-077c-400e-ac58-cebd0719ff80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610497,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"2356bf77-077c-400e-ac58-cebd0719ff80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610497,\"participants\":[{\"id\":996401,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996402,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"2356bf77-077c-400e-ac58-cebd0719ff80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"2356bf77-077c-400e-ac58-cebd0719ff80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"2356bf77-077c-400e-ac58-cebd0719ff80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"2356bf77-077c-400e-ac58-cebd0719ff80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"2356bf77-077c-400e-ac58-cebd0719ff80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"2356bf77-077c-400e-ac58-cebd0719ff80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"2356bf77-077c-400e-ac58-cebd0719ff80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.WARNING: [Hubspot] No retry-after header or policy name found, using default {\"exception_class\":\"SevenShores\\\\Hubspot\\\\Exceptions\\\\BadRequest\"} {\"correlation_id\":\"2356bf77-077c-400e-ac58-cebd0719ff80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.WARNING: [Hubspot] Received 429 from API {\"team_id\":2,\"config_id\":2,\"retry_after\":10,\"policy\":null,\"reason\":\"Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response:\n{\\\"status\\\":\\\"error\\\",\\\"message\\\":\\\"You have reached your secondly limit.\\\",\\\"errorType\\\":\\\"RATE_LIMIT\\\",\\\"correlationId\\\":\\\"019e168a-c (truncated...)\n\"} {\"correlation_id\":\"2356bf77-077c-400e-ac58-cebd0719ff80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":12} {\"correlation_id\":\"2356bf77-077c-400e-ac58-cebd0719ff80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610490,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"2e2173eb-7d9e-43e9-b8e2-2c6bb1d4c684\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610490} {\"correlation_id\":\"2e2173eb-7d9e-43e9-b8e2-2c6bb1d4c684\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610490,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"2e2173eb-7d9e-43e9-b8e2-2c6bb1d4c684\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610490,\"participants\":[{\"id\":996385,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996386,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"2e2173eb-7d9e-43e9-b8e2-2c6bb1d4c684\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"2e2173eb-7d9e-43e9-b8e2-2c6bb1d4c684\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"2e2173eb-7d9e-43e9-b8e2-2c6bb1d4c684\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"2e2173eb-7d9e-43e9-b8e2-2c6bb1d4c684\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"2e2173eb-7d9e-43e9-b8e2-2c6bb1d4c684\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"2e2173eb-7d9e-43e9-b8e2-2c6bb1d4c684\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"2e2173eb-7d9e-43e9-b8e2-2c6bb1d4c684\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":10} {\"correlation_id\":\"2e2173eb-7d9e-43e9-b8e2-2c6bb1d4c684\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610470,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"63a0af1c-277e-446c-9a48-9757a8d34ddc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610470} {\"correlation_id\":\"63a0af1c-277e-446c-9a48-9757a8d34ddc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610470,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"63a0af1c-277e-446c-9a48-9757a8d34ddc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610470,\"participants\":[{\"id\":996369,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996370,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"63a0af1c-277e-446c-9a48-9757a8d34ddc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"63a0af1c-277e-446c-9a48-9757a8d34ddc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"63a0af1c-277e-446c-9a48-9757a8d34ddc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"63a0af1c-277e-446c-9a48-9757a8d34ddc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"63a0af1c-277e-446c-9a48-9757a8d34ddc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"63a0af1c-277e-446c-9a48-9757a8d34ddc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"63a0af1c-277e-446c-9a48-9757a8d34ddc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":15} {\"correlation_id\":\"63a0af1c-277e-446c-9a48-9757a8d34ddc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610462,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"b324376c-1fd3-497f-b0fb-004f86f50635\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610462} {\"correlation_id\":\"b324376c-1fd3-497f-b0fb-004f86f50635\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610462,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"b324376c-1fd3-497f-b0fb-004f86f50635\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610462,\"participants\":[{\"id\":996353,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996354,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"b324376c-1fd3-497f-b0fb-004f86f50635\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b324376c-1fd3-497f-b0fb-004f86f50635\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b324376c-1fd3-497f-b0fb-004f86f50635\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"b324376c-1fd3-497f-b0fb-004f86f50635\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"b324376c-1fd3-497f-b0fb-004f86f50635\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"b324376c-1fd3-497f-b0fb-004f86f50635\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"b324376c-1fd3-497f-b0fb-004f86f50635\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"b324376c-1fd3-497f-b0fb-004f86f50635\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610451,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"b2b3cc5b-60ce-4c18-bb68-76d30013357c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610451} {\"correlation_id\":\"b2b3cc5b-60ce-4c18-bb68-76d30013357c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610451,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"b2b3cc5b-60ce-4c18-bb68-76d30013357c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610451,\"participants\":[{\"id\":996340,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996341,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"b2b3cc5b-60ce-4c18-bb68-76d30013357c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b2b3cc5b-60ce-4c18-bb68-76d30013357c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b2b3cc5b-60ce-4c18-bb68-76d30013357c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"b2b3cc5b-60ce-4c18-bb68-76d30013357c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"b2b3cc5b-60ce-4c18-bb68-76d30013357c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"b2b3cc5b-60ce-4c18-bb68-76d30013357c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"b2b3cc5b-60ce-4c18-bb68-76d30013357c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"b2b3cc5b-60ce-4c18-bb68-76d30013357c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610438,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"d6026499-3681-474a-85f7-3faee13605b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610438} {\"correlation_id\":\"d6026499-3681-474a-85f7-3faee13605b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610438,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"d6026499-3681-474a-85f7-3faee13605b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610438,\"participants\":[{\"id\":996320,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996321,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"d6026499-3681-474a-85f7-3faee13605b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"d6026499-3681-474a-85f7-3faee13605b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"d6026499-3681-474a-85f7-3faee13605b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"d6026499-3681-474a-85f7-3faee13605b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"d6026499-3681-474a-85f7-3faee13605b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"d6026499-3681-474a-85f7-3faee13605b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"d6026499-3681-474a-85f7-3faee13605b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":13} {\"correlation_id\":\"d6026499-3681-474a-85f7-3faee13605b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610426,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"17b3d9a6-2eb0-49d1-8a00-c67c644885e1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610426} {\"correlation_id\":\"17b3d9a6-2eb0-49d1-8a00-c67c644885e1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610426,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"17b3d9a6-2eb0-49d1-8a00-c67c644885e1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610426,\"participants\":[{\"id\":996306,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996307,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"17b3d9a6-2eb0-49d1-8a00-c67c644885e1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"17b3d9a6-2eb0-49d1-8a00-c67c644885e1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"17b3d9a6-2eb0-49d1-8a00-c67c644885e1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"17b3d9a6-2eb0-49d1-8a00-c67c644885e1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"17b3d9a6-2eb0-49d1-8a00-c67c644885e1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"17b3d9a6-2eb0-49d1-8a00-c67c644885e1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"17b3d9a6-2eb0-49d1-8a00-c67c644885e1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":15} {\"correlation_id\":\"17b3d9a6-2eb0-49d1-8a00-c67c644885e1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610403,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"112a2c70-a5f2-4500-9726-7f560d683236\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610403} {\"correlation_id\":\"112a2c70-a5f2-4500-9726-7f560d683236\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610403,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"112a2c70-a5f2-4500-9726-7f560d683236\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610403,\"participants\":[{\"id\":996282,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996283,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"112a2c70-a5f2-4500-9726-7f560d683236\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"112a2c70-a5f2-4500-9726-7f560d683236\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"112a2c70-a5f2-4500-9726-7f560d683236\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"112a2c70-a5f2-4500-9726-7f560d683236\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"112a2c70-a5f2-4500-9726-7f560d683236\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"112a2c70-a5f2-4500-9726-7f560d683236\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"112a2c70-a5f2-4500-9726-7f560d683236\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"112a2c70-a5f2-4500-9726-7f560d683236\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610400,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":350,\"stage_id\":34}} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610400} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610400,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610400,\"participants\":[{\"id\":996275,\"user_id\":1460,\"contact_id\":null,\"lead_id\":null},{\"id\":996276,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":996277,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null}]} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610400,\"team_id\":2,\"email\":\"aneliya.angelova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610400,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: ProspectCache - Searching DB for opportunity by owner {\"account_id\":244,\"contact_id\":4487,\"owner_id\":1460} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: ProspectCache - Fallback DB opportunity search {\"account_id\":244,\"contact_id\":4487} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: ProspectCache - Opportunity DB search results {\"account_id\":244,\"contact_id\":4487,\"opportunity_id\":350} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610400,\"participants_processed\":3,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610400} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610400,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610400,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":350,\"stage_id\":34} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614381,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6868b438-d843-4331-9862-f802e4cc4ff2\"}\n[2026-05-11 10:17:34] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614381} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6868b438-d843-4331-9862-f802e4cc4ff2\"}\n[2026-05-11 10:17:34] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614381,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6868b438-d843-4331-9862-f802e4cc4ff2\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614381,\"participants\":[{\"id\":1002630,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002631,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6868b438-d843-4331-9862-f802e4cc4ff2\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6868b438-d843-4331-9862-f802e4cc4ff2\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6868b438-d843-4331-9862-f802e4cc4ff2\"}\n[2026-05-11 10:17:34] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6868b438-d843-4331-9862-f802e4cc4ff2\"}\n[2026-05-11 10:17:34] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6868b438-d843-4331-9862-f802e4cc4ff2\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6868b438-d843-4331-9862-f802e4cc4ff2\"}\n[2026-05-11 10:17:34] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"nikolay.nikolov@jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/nikolay.nikolov%40jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6868b438-d843-4331-9862-f802e4cc4ff2\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6868b438-d843-4331-9862-f802e4cc4ff2\"}\n[2026-05-11 10:17:34] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":10} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6868b438-d843-4331-9862-f802e4cc4ff2\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614382,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f600c314-da4f-48ea-885b-f3b0db553881\"}\n[2026-05-11 10:17:34] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614382} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f600c314-da4f-48ea-885b-f3b0db553881\"}\n[2026-05-11 10:17:34] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614382,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f600c314-da4f-48ea-885b-f3b0db553881\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614382,\"participants\":[{\"id\":1002632,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002633,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f600c314-da4f-48ea-885b-f3b0db553881\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f600c314-da4f-48ea-885b-f3b0db553881\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f600c314-da4f-48ea-885b-f3b0db553881\"}\n[2026-05-11 10:17:34] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f600c314-da4f-48ea-885b-f3b0db553881\"}\n[2026-05-11 10:17:34] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f600c314-da4f-48ea-885b-f3b0db553881\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f600c314-da4f-48ea-885b-f3b0db553881\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f600c314-da4f-48ea-885b-f3b0db553881\"}\n[2026-05-11 10:17:34] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":10} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f600c314-da4f-48ea-885b-f3b0db553881\"}\n[2026-05-11 10:17:34] local.NOTICE: Monitoring start {\"correlation_id\":\"2a3353ba-9883-42be-b596-9e38bd5fc160\",\"trace_id\":\"fc84fbbd-f6ab-40f6-8fdc-f023fbe3b46e\"}\n[2026-05-11 10:17:34] local.NOTICE: Monitoring end {\"correlation_id\":\"2a3353ba-9883-42be-b596-9e38bd5fc160\",\"trace_id\":\"fc84fbbd-f6ab-40f6-8fdc-f023fbe3b46e\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612819,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ac88094e-4a12-4e5c-87dd-c7701d7a8719\"}\n[2026-05-11 10:17:34] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612819} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ac88094e-4a12-4e5c-87dd-c7701d7a8719\"}\n[2026-05-11 10:17:34] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612819,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ac88094e-4a12-4e5c-87dd-c7701d7a8719\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612819,\"participants\":[{\"id\":1000073,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1000074,\"user_id\":261,\"contact_id\":null,\"lead_id\":null},{\"id\":1000075,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ac88094e-4a12-4e5c-87dd-c7701d7a8719\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ac88094e-4a12-4e5c-87dd-c7701d7a8719\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ac88094e-4a12-4e5c-87dd-c7701d7a8719\"}\n[2026-05-11 10:17:34] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ac88094e-4a12-4e5c-87dd-c7701d7a8719\"}\n[2026-05-11 10:17:34] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ac88094e-4a12-4e5c-87dd-c7701d7a8719\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ac88094e-4a12-4e5c-87dd-c7701d7a8719\"}\n[2026-05-11 10:17:34] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612819,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ac88094e-4a12-4e5c-87dd-c7701d7a8719\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ac88094e-4a12-4e5c-87dd-c7701d7a8719\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ac88094e-4a12-4e5c-87dd-c7701d7a8719\"}\n[2026-05-11 10:17:34] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":11} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ac88094e-4a12-4e5c-87dd-c7701d7a8719\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":615092,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"5b7869a5-e05c-417f-819f-12774e20bb56\"}\n[2026-05-11 10:17:34] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":615092} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"5b7869a5-e05c-417f-819f-12774e20bb56\"}\n[2026-05-11 10:17:34] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":615092,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"5b7869a5-e05c-417f-819f-12774e20bb56\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":615092,\"participants\":[{\"id\":1004102,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1004103,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"5b7869a5-e05c-417f-819f-12774e20bb56\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"5b7869a5-e05c-417f-819f-12774e20bb56\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"5b7869a5-e05c-417f-819f-12774e20bb56\"}\n[2026-05-11 10:17:34] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"5b7869a5-e05c-417f-819f-12774e20bb56\"}\n[2026-05-11 10:17:34] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"5b7869a5-e05c-417f-819f-12774e20bb56\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"5b7869a5-e05c-417f-819f-12774e20bb56\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"5b7869a5-e05c-417f-819f-12774e20bb56\"}\n[2026-05-11 10:17:34] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":14} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"5b7869a5-e05c-417f-819f-12774e20bb56\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614436,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72bb1bed-9270-436f-977c-a73c970415a3\"}\n[2026-05-11 10:17:34] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614436} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72bb1bed-9270-436f-977c-a73c970415a3\"}\n[2026-05-11 10:17:34] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614436,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72bb1bed-9270-436f-977c-a73c970415a3\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614436,\"participants\":[{\"id\":1002751,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002752,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72bb1bed-9270-436f-977c-a73c970415a3\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72bb1bed-9270-436f-977c-a73c970415a3\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72bb1bed-9270-436f-977c-a73c970415a3\"}\n[2026-05-11 10:17:34] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72bb1bed-9270-436f-977c-a73c970415a3\"}\n[2026-05-11 10:17:34] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72bb1bed-9270-436f-977c-a73c970415a3\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72bb1bed-9270-436f-977c-a73c970415a3\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72bb1bed-9270-436f-977c-a73c970415a3\"}\n[2026-05-11 10:17:34] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":13} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72bb1bed-9270-436f-977c-a73c970415a3\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614378,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":6167,\"account_id\":null,\"opportunity_id\":null,\"stage_id\":null}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ef02c9ff-d0fc-47cb-aeb0-e8ba837de699\"}\n[2026-05-11 10:17:34] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614378} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ef02c9ff-d0fc-47cb-aeb0-e8ba837de699\"}\n[2026-05-11 10:17:34] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614378,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ef02c9ff-d0fc-47cb-aeb0-e8ba837de699\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614378,\"participants\":[{\"id\":1002623,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002624,\"user_id\":null,\"contact_id\":6167,\"lead_id\":null},{\"id\":1002625,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ef02c9ff-d0fc-47cb-aeb0-e8ba837de699\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ef02c9ff-d0fc-47cb-aeb0-e8ba837de699\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ef02c9ff-d0fc-47cb-aeb0-e8ba837de699\"}\n[2026-05-11 10:17:34] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ef02c9ff-d0fc-47cb-aeb0-e8ba837de699\"}\n[2026-05-11 10:17:34] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ef02c9ff-d0fc-47cb-aeb0-e8ba837de699\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ef02c9ff-d0fc-47cb-aeb0-e8ba837de699\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ef02c9ff-d0fc-47cb-aeb0-e8ba837de699\"}\n[2026-05-11 10:17:34] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":12} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ef02c9ff-d0fc-47cb-aeb0-e8ba837de699\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612847,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e1608ca2-4101-4e24-8c9f-29ba81ce925f\"}\n[2026-05-11 10:17:34] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612847} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e1608ca2-4101-4e24-8c9f-29ba81ce925f\"}\n[2026-05-11 10:17:34] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612847,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e1608ca2-4101-4e24-8c9f-29ba81ce925f\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612847,\"participants\":[{\"id\":1000130,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1000131,\"user_id\":261,\"contact_id\":null,\"lead_id\":null},{\"id\":1000151,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e1608ca2-4101-4e24-8c9f-29ba81ce925f\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e1608ca2-4101-4e24-8c9f-29ba81ce925f\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e1608ca2-4101-4e24-8c9f-29ba81ce925f\"}\n[2026-05-11 10:17:34] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e1608ca2-4101-4e24-8c9f-29ba81ce925f\"}\n[2026-05-11 10:17:34] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e1608ca2-4101-4e24-8c9f-29ba81ce925f\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e1608ca2-4101-4e24-8c9f-29ba81ce925f\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e1608ca2-4101-4e24-8c9f-29ba81ce925f\"}\n[2026-05-11 10:17:34] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":11} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e1608ca2-4101-4e24-8c9f-29ba81ce925f\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612562,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"40f1c570-c73a-4bea-99d1-0b405485c1eb\"}\n[2026-05-11 10:17:34] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612562} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"40f1c570-c73a-4bea-99d1-0b405485c1eb\"}\n[2026-05-11 10:17:34] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612562,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"40f1c570-c73a-4bea-99d1-0b405485c1eb\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612562,\"participants\":[{\"id\":999782,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999783,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"40f1c570-c73a-4bea-99d1-0b405485c1eb\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"40f1c570-c73a-4bea-99d1-0b405485c1eb\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"40f1c570-c73a-4bea-99d1-0b405485c1eb\"}\n[2026-05-11 10:17:34] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"40f1c570-c73a-4bea-99d1-0b405485c1eb\"}\n[2026-05-11 10:17:34] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"40f1c570-c73a-4bea-99d1-0b405485c1eb\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"40f1c570-c73a-4bea-99d1-0b405485c1eb\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"40f1c570-c73a-4bea-99d1-0b405485c1eb\"}\n[2026-05-11 10:17:34] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":14} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"40f1c570-c73a-4bea-99d1-0b405485c1eb\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612560,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6f43c701-78e8-4a90-bc73-feecc83e035c\"}\n[2026-05-11 10:17:34] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612560} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6f43c701-78e8-4a90-bc73-feecc83e035c\"}\n[2026-05-11 10:17:34] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612560,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6f43c701-78e8-4a90-bc73-feecc83e035c\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612560,\"participants\":[{\"id\":999778,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999779,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6f43c701-78e8-4a90-bc73-feecc83e035c\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6f43c701-78e8-4a90-bc73-feecc83e035c\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6f43c701-78e8-4a90-bc73-feecc83e035c\"}\n[2026-05-11 10:17:34] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6f43c701-78e8-4a90-bc73-feecc83e035c\"}\n[2026-05-11 10:17:34] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6f43c701-78e8-4a90-bc73-feecc83e035c\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6f43c701-78e8-4a90-bc73-feecc83e035c\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6f43c701-78e8-4a90-bc73-feecc83e035c\"}\n[2026-05-11 10:17:34] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":10} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6f43c701-78e8-4a90-bc73-feecc83e035c\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612561,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"714584dc-ec4b-479a-aecd-db6c109f4a6d\"}\n[2026-05-11 10:17:34] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612561} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"714584dc-ec4b-479a-aecd-db6c109f4a6d\"}\n[2026-05-11 10:17:34] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612561,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"714584dc-ec4b-479a-aecd-db6c109f4a6d\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612561,\"participants\":[{\"id\":999780,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999781,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"714584dc-ec4b-479a-aecd-db6c109f4a6d\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"714584dc-ec4b-479a-aecd-db6c109f4a6d\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"714584dc-ec4b-479a-aecd-db6c109f4a6d\"}\n[2026-05-11 10:17:34] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"714584dc-ec4b-479a-aecd-db6c109f4a6d\"}\n[2026-05-11 10:17:34] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"714584dc-ec4b-479a-aecd-db6c109f4a6d\"}\n[2026-05-11 10:17:34] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612561,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"714584dc-ec4b-479a-aecd-db6c109f4a6d\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"447700174614.447782589921.OeREojLVnk@txt.staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"714584dc-ec4b-479a-aecd-db6c109f4a6d\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"447700174614.447782589921.OeREojLVnk@txt.staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"714584dc-ec4b-479a-aecd-db6c109f4a6d\"}\n[2026-05-11 10:17:34] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":12} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"714584dc-ec4b-479a-aecd-db6c109f4a6d\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612340,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f7f53665-81f1-4b01-86eb-56ad96f088db\"}\n[2026-05-11 10:17:34] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612340} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f7f53665-81f1-4b01-86eb-56ad96f088db\"}\n[2026-05-11 10:17:34] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612340,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f7f53665-81f1-4b01-86eb-56ad96f088db\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612340,\"participants\":[{\"id\":999516,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999517,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999518,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999519,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f7f53665-81f1-4b01-86eb-56ad96f088db\"}\n[2026-05-11 10:17:35] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f7f53665-81f1-4b01-86eb-56ad96f088db\"}\n[2026-05-11 10:17:35] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f7f53665-81f1-4b01-86eb-56ad96f088db\"}\n[2026-05-11 10:17:35] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f7f53665-81f1-4b01-86eb-56ad96f088db\"}\n[2026-05-11 10:17:35] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f7f53665-81f1-4b01-86eb-56ad96f088db\"}\n[2026-05-11 10:17:35] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f7f53665-81f1-4b01-86eb-56ad96f088db\"}\n[2026-05-11 10:17:35] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612340,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f7f53665-81f1-4b01-86eb-56ad96f088db\"}\n[2026-05-11 10:17:35] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":14} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f7f53665-81f1-4b01-86eb-56ad96f088db\"}\n[2026-05-11 10:17:35] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612360,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7356be9b-68c6-4c39-9fbe-d16bafce4614\"}\n[2026-05-11 10:17:35] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612360} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7356be9b-68c6-4c39-9fbe-d16bafce4614\"}\n[2026-05-11 10:17:35] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612360,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7356be9b-68c6-4c39-9fbe-d16bafce4614\"}\n[2026-05-11 10:17:35] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612360,\"participants\":[{\"id\":999552,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999553,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999565,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7356be9b-68c6-4c39-9fbe-d16bafce4614\"}\n[2026-05-11 10:17:35] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7356be9b-68c6-4c39-9fbe-d16bafce4614\"}\n[2026-05-11 10:17:35] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7356be9b-68c6-4c39-9fbe-d16bafce4614\"}\n[2026-05-11 10:17:35] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7356be9b-68c6-4c39-9fbe-d16bafce4614\"}\n[2026-05-11 10:17:35] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7356be9b-68c6-4c39-9fbe-d16bafce4614\"}\n[2026-05-11 10:17:35] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7356be9b-68c6-4c39-9fbe-d16bafce4614\"}\n[2026-05-11 10:17:35] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612360,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7356be9b-68c6-4c39-9fbe-d16bafce4614\"}\n[2026-05-11 10:17:35] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":15} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7356be9b-68c6-4c39-9fbe-d16bafce4614\"}\n[2026-05-11 10:17:35] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612339,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb97cad3-6d10-4315-a771-a5c3a8aeeb31\"}\n[2026-05-11 10:17:35] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612339} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb97cad3-6d10-4315-a771-a5c3a8aeeb31\"}\n[2026-05-11 10:17:35] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612339,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb97cad3-6d10-4315-a771-a5c3a8aeeb31\"}\n[2026-05-11 10:17:35] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612339,\"participants\":[{\"id\":999514,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999515,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999540,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb97cad3-6d10-4315-a771-a5c3a8aeeb31\"}\n[2026-05-11 10:17:35] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb97cad3-6d10-4315-a771-a5c3a8aeeb31\"}\n[2026-05-11 10:17:35] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb97cad3-6d10-4315-a771-a5c3a8aeeb31\"}\n[2026-05-11 10:17:35] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb97cad3-6d10-4315-a771-a5c3a8aeeb31\"}\n[2026-05-11 10:17:35] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb97cad3-6d10-4315-a771-a5c3a8aeeb31\"}\n[2026-05-11 10:17:35] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb97cad3-6d10-4315-a771-a5c3a8aeeb31\"}\n[2026-05-11 10:17:35] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612339,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb97cad3-6d10-4315-a771-a5c3a8aeeb31\"}\n[2026-05-11 10:17:35] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":15} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb97cad3-6d10-4315-a771-a5c3a8aeeb31\"}\n[2026-05-11 10:17:36] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"b6a9ae37-beff-496a-820a-bcf0512308f2\",\"trace_id\":\"be38fb3e-0cfa-4c02-a66a-cc0cf8d3d54a\"}\n[2026-05-11 10:17:36] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"b6a9ae37-beff-496a-820a-bcf0512308f2\",\"trace_id\":\"be38fb3e-0cfa-4c02-a66a-cc0cf8d3d54a\"}\n[2026-05-11 10:17:37] local.INFO: [ EsUpdateProcessManager ] Finished updating entities in ES {\"worker\":\"\",\"peak_memory\":\"99.73 MB\",\"elapsed_seconds\":0.49,\"update_target\":\"activities\",\"should_iterate_again\":false} {\"correlation_id\":\"4ad05333-9afb-492e-9f0f-b2909ac45b32\",\"trace_id\":\"3d8feb24-b173-4158-b0a4-4cf33af85066\"}\n[2026-05-11 10:17:37] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611451,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73d4c333-df67-43c5-a413-4c675a3ebc5e\"}\n[2026-05-11 10:17:37] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611451} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73d4c333-df67-43c5-a413-4c675a3ebc5e\"}\n[2026-05-11 10:17:37] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611451,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73d4c333-df67-43c5-a413-4c675a3ebc5e\"}\n[2026-05-11 10:17:37] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611451,\"participants\":[{\"id\":997955,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997956,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73d4c333-df67-43c5-a413-4c675a3ebc5e\"}\n[2026-05-11 10:17:37] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73d4c333-df67-43c5-a413-4c675a3ebc5e\"}\n[2026-05-11 10:17:37] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73d4c333-df67-43c5-a413-4c675a3ebc5e\"}\n[2026-05-11 10:17:37] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73d4c333-df67-43c5-a413-4c675a3ebc5e\"}\n[2026-05-11 10:17:37] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73d4c333-df67-43c5-a413-4c675a3ebc5e\"}\n[2026-05-11 10:17:37] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73d4c333-df67-43c5-a413-4c675a3ebc5e\"}\n[2026-05-11 10:17:37] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73d4c333-df67-43c5-a413-4c675a3ebc5e\"}\n[2026-05-11 10:17:37] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":12} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73d4c333-df67-43c5-a413-4c675a3ebc5e\"}\n[2026-05-11 10:17:37] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611087,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0c0e087e-66cf-4404-b647-530f77b3e652\"}\n[2026-05-11 10:17:37] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611087} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0c0e087e-66cf-4404-b647-530f77b3e652\"}\n[2026-05-11 10:17:37] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611087,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0c0e087e-66cf-4404-b647-530f77b3e652\"}\n[2026-05-11 10:17:37] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611087,\"participants\":[{\"id\":997368,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997369,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0c0e087e-66cf-4404-b647-530f77b3e652\"}\n[2026-05-11 10:17:37] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0c0e087e-66cf-4404-b647-530f77b3e652\"}\n[2026-05-11 10:17:37] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0c0e087e-66cf-4404-b647-530f77b3e652\"}\n[2026-05-11 10:17:37] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0c0e087e-66cf-4404-b647-530f77b3e652\"}\n[2026-05-11 10:17:37] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0c0e087e-66cf-4404-b647-530f77b3e652\"}\n[2026-05-11 10:17:37] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0c0e087e-66cf-4404-b647-530f77b3e652\"}\n[2026-05-11 10:17:37] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0c0e087e-66cf-4404-b647-530f77b3e652\"}\n[2026-05-11 10:17:37] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":14} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0c0e087e-66cf-4404-b647-530f77b3e652\"}\n[2026-05-11 10:17:37] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611076,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8ae56005-eaea-4862-83a4-4c28e0deb862\"}\n[2026-05-11 10:17:37] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611076} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8ae56005-eaea-4862-83a4-4c28e0deb862\"}\n[2026-05-11 10:17:37] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611076,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8ae56005-eaea-4862-83a4-4c28e0deb862\"}\n[2026-05-11 10:17:37] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611076,\"participants\":[{\"id\":997346,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997347,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8ae56005-eaea-4862-83a4-4c28e0deb862\"}\n[2026-05-11 10:17:37] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8ae56005-eaea-4862-83a4-4c28e0deb862\"}\n[2026-05-11 10:17:37] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8ae56005-eaea-4862-83a4-4c28e0deb862\"}\n[2026-05-11 10:17:37] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8ae56005-eaea-4862-83a4-4c28e0deb862\"}\n[2026-05-11 10:17:37] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8ae56005-eaea-4862-83a4-4c28e0deb862\"}\n[2026-05-11 10:17:37] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8ae56005-eaea-4862-83a4-4c28e0deb862\"}\n[2026-05-11 10:17:37] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8ae56005-eaea-4862-83a4-4c28e0deb862\"}\n[2026-05-11 10:17:37] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":15} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8ae56005-eaea-4862-83a4-4c28e0deb862\"}\n[2026-05-11 10:17:38] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610900,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72f691bf-4dd5-46e4-b0aa-e6d9947e244c\"}\n[2026-05-11 10:17:38] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610900} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72f691bf-4dd5-46e4-b0aa-e6d9947e244c\"}\n[2026-05-11 10:17:38] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610900,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72f691bf-4dd5-46e4-b0aa-e6d9947e244c\"}\n[2026-05-11 10:17:38] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610900,\"participants\":[{\"id\":997081,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997082,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72f691bf-4dd5-46e4-b0aa-e6d9947e244c\"}\n[2026-05-11 10:17:38] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72f691bf-4dd5-46e4-b0aa-e6d9947e244c\"}\n[2026-05-11 10:17:38] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72f691bf-4dd5-46e4-b0aa-e6d9947e244c\"}\n[2026-05-11 10:17:38] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72f691bf-4dd5-46e4-b0aa-e6d9947e244c\"}\n[2026-05-11 10:17:38] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72f691bf-4dd5-46e4-b0aa-e6d9947e244c\"}\n[2026-05-11 10:17:38] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72f691bf-4dd5-46e4-b0aa-e6d9947e244c\"}\n[2026-05-11 10:17:38] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72f691bf-4dd5-46e4-b0aa-e6d9947e244c\"}\n[2026-05-11 10:17:38] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":10} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72f691bf-4dd5-46e4-b0aa-e6d9947e244c\"}\n[2026-05-11 10:17:38] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610935,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9c039918-1cd4-4208-bd24-8e42d3efb19e\"}\n[2026-05-11 10:17:38] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610935} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9c039918-1cd4-4208-bd24-8e42d3efb19e\"}\n[2026-05-11 10:17:38] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610935,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9c039918-1cd4-4208-bd24-8e42d3efb19e\"}\n[2026-05-11 10:17:38] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610935,\"participants\":[{\"id\":997141,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997142,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9c039918-1cd4-4208-bd24-8e42d3efb19e\"}\n[2026-05-11 10:17:38] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9c039918-1cd4-4208-bd24-8e42d3efb19e\"}\n[2026-05-11 10:17:38] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9c039918-1cd4-4208-bd24-8e42d3efb19e\"}\n[2026-05-11 10:17:38] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9c039918-1cd4-4208-bd24-8e42d3efb19e\"}\n[2026-05-11 10:17:38] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9c039918-1cd4-4208-bd24-8e42d3efb19e\"}\n[2026-05-11 10:17:38] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9c039918-1cd4-4208-bd24-8e42d3efb19e\"}\n[2026-05-11 10:17:38] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9c039918-1cd4-4208-bd24-8e42d3efb19e\"}\n[2026-05-11 10:17:38] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":10} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9c039918-1cd4-4208-bd24-8e42d3efb19e\"}\n[2026-05-11 10:17:39] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"07a987cd-1db5-4796-b217-d8d2d1b6913e\",\"trace_id\":\"90eeb583-f4ef-4d3f-bf6e-2425312728c5\"}\n[2026-05-11 10:17:39] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"07a987cd-1db5-4796-b217-d8d2d1b6913e\",\"trace_id\":\"90eeb583-f4ef-4d3f-bf6e-2425312728c5\"}\n[2026-05-11 10:17:39] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"07a987cd-1db5-4796-b217-d8d2d1b6913e\",\"trace_id\":\"90eeb583-f4ef-4d3f-bf6e-2425312728c5\"}\n[2026-05-11 10:17:39] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"07a987cd-1db5-4796-b217-d8d2d1b6913e\",\"trace_id\":\"90eeb583-f4ef-4d3f-bf6e-2425312728c5\"}\n[2026-05-11 10:17:39] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612336,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"207e2c1f-73c1-428d-80a6-3c87aa383443\"}\n[2026-05-11 10:17:39] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612336} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"207e2c1f-73c1-428d-80a6-3c87aa383443\"}\n[2026-05-11 10:17:39] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612336,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"207e2c1f-73c1-428d-80a6-3c87aa383443\"}\n[2026-05-11 10:17:39] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612336,\"participants\":[{\"id\":999508,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999509,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999512,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999513,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"207e2c1f-73c1-428d-80a6-3c87aa383443\"}\n[2026-05-11 10:17:39] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"207e2c1f-73c1-428d-80a6-3c87aa383443\"}\n[2026-05-11 10:17:39] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"207e2c1f-73c1-428d-80a6-3c87aa383443\"}\n[2026-05-11 10:17:39] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"207e2c1f-73c1-428d-80a6-3c87aa383443\"}\n[2026-05-11 10:17:39] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"207e2c1f-73c1-428d-80a6-3c87aa383443\"}\n[2026-05-11 10:17:39] local.INFO: ProspectCache - Searching DB for opportunity by owner {\"account_id\":243,\"contact_id\":4491,\"owner_id\":206} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"207e2c1f-73c1-428d-80a6-3c87aa383443\"}\n[2026-05-11 10:17:39] local.INFO: ProspectCache - Fallback DB opportunity search {\"account_id\":243,\"contact_id\":4491} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"207e2c1f-73c1-428d-80a6-3c87aa383443\"}\n[2026-05-11 10:17:39] local.INFO: ProspectCache - Opportunity DB search results {\"account_id\":243,\"contact_id\":4491,\"opportunity_id\":276} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"207e2c1f-73c1-428d-80a6-3c87aa383443\"}\n[2026-05-11 10:17:39] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"207e2c1f-73c1-428d-80a6-3c87aa383443\"}\n[2026-05-11 10:17:39] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612336,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"207e2c1f-73c1-428d-80a6-3c87aa383443\"}\n[2026-05-11 10:17:39] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":10} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"207e2c1f-73c1-428d-80a6-3c87aa383443\"}\n[2026-05-11 10:17:40] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611455,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3b238a85-6f7e-44ab-8dac-2e8f132b32fe\"}\n[2026-05-11 10:17:40] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611455} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3b238a85-6f7e-44ab-8dac-2e8f132b32fe\"}\n[2026-05-11 10:17:40] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611455,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3b238a85-6f7e-44ab-8dac-2e8f132b32fe\"}\n[2026-05-11 10:17:40] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611455,\"participants\":[{\"id\":997961,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997962,\"user_id\":1460,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3b238a85-6f7e-44ab-8dac-2e8f132b32fe\"}\n[2026-05-11 10:17:40] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3b238a85-6f7e-44ab-8dac-2e8f132b32fe\"}\n[2026-05-11 10:17:40] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3b238a85-6f7e-44ab-8dac-2e8f132b32fe\"}\n[2026-05-11 10:17:40] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3b238a85-6f7e-44ab-8dac-2e8f132b32fe\"}\n[2026-05-11 10:17:40] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3b238a85-6f7e-44ab-8dac-2e8f132b32fe\"}\n[2026-05-11 10:17:40] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3b238a85-6f7e-44ab-8dac-2e8f132b32fe\"}\n[2026-05-11 10:17:40] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3b238a85-6f7e-44ab-8dac-2e8f132b32fe\"}\n[2026-05-11 10:17:40] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":12} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3b238a85-6f7e-44ab-8dac-2e8f132b32fe\"}\n[2026-05-11 10:17:40] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610878,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"233b41da-91f2-45fb-8a21-80d2cd24570d\"}\n[2026-05-11 10:17:40] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610878} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"233b41da-91f2-45fb-8a21-80d2cd24570d\"}\n[2026-05-11 10:17:40] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610878,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"233b41da-91f2-45fb-8a21-80d2cd24570d\"}\n[2026-05-11 10:17:40] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610878,\"participants\":[{\"id\":997035,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997036,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"233b41da-91f2-45fb-8a21-80d2cd24570d\"}\n[2026-05-11 10:17:40] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"233b41da-91f2-45fb-8a21-80d2cd24570d\"}\n[2026-05-11 10:17:40] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"233b41da-91f2-45fb-8a21-80d2cd24570d\"}\n[2026-05-11 10:17:40] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"233b41da-91f2-45fb-8a21-80d2cd24570d\"}\n[2026-05-11 10:17:40] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"233b41da-91f2-45fb-8a21-80d2cd24570d\"}\n[2026-05-11 10:17:40] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"233b41da-91f2-45fb-8a21-80d2cd24570d\"}\n[2026-05-11 10:17:40] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"233b41da-91f2-45fb-8a21-80d2cd24570d\"}\n[2026-05-11 10:17:40] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":13} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"233b41da-91f2-45fb-8a21-80d2cd24570d\"}\n[2026-05-11 10:17:41] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:create\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"e17eab55-f6ef-40c4-bcf7-0b2b4af23908\",\"trace_id\":\"fab32d53-3e12-42b6-b809-50dcad19899b\"}\n[2026-05-11 10:17:41] local.INFO: [EmailSchedule] STARTING batch create {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"e17eab55-f6ef-40c4-bcf7-0b2b4af23908\",\"trace_id\":\"fab32d53-3e12-42b6-b809-50dcad19899b\"}\n[2026-05-11 10:17:41] local.INFO: [EmailSchedule] FINISHED batch create {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"e17eab55-f6ef-40c4-bcf7-0b2b4af23908\",\"trace_id\":\"fab32d53-3e12-42b6-b809-50dcad19899b\"}\n[2026-05-11 10:17:41] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:create\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"e17eab55-f6ef-40c4-bcf7-0b2b4af23908\",\"trace_id\":\"fab32d53-3e12-42b6-b809-50dcad19899b\"}\n[2026-05-11 10:17:41] local.INFO: [Jiminny\\Jobs\\Mailbox\\CreateBatches] processed 2 inboxes and created 0 batches {\"userId\":null,\"batchSize\":30,\"maxBatches\":1000} {\"correlation_id\":\"f6431de6-0cbf-4083-96fc-d316ebac17ec\",\"trace_id\":\"fab32d53-3e12-42b6-b809-50dcad19899b\"}\n[2026-05-11 10:17:42] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610539,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ae1e1745-b1f8-4fa9-9d96-b0ec9934cbbd\"}\n[2026-05-11 10:17:42] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610539} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ae1e1745-b1f8-4fa9-9d96-b0ec9934cbbd\"}\n[2026-05-11 10:17:42] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610539,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ae1e1745-b1f8-4fa9-9d96-b0ec9934cbbd\"}\n[2026-05-11 10:17:42] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610539,\"participants\":[{\"id\":996485,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996486,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ae1e1745-b1f8-4fa9-9d96-b0ec9934cbbd\"}\n[2026-05-11 10:17:42] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ae1e1745-b1f8-4fa9-9d96-b0ec9934cbbd\"}\n[2026-05-11 10:17:42] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ae1e1745-b1f8-4fa9-9d96-b0ec9934cbbd\"}\n[2026-05-11 10:17:42] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ae1e1745-b1f8-4fa9-9d96-b0ec9934cbbd\"}\n[2026-05-11 10:17:42] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ae1e1745-b1f8-4fa9-9d96-b0ec9934cbbd\"}\n[2026-05-11 10:17:42] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ae1e1745-b1f8-4fa9-9d96-b0ec9934cbbd\"}\n[2026-05-11 10:17:42] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ae1e1745-b1f8-4fa9-9d96-b0ec9934cbbd\"}\n[2026-05-11 10:17:42] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":11} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ae1e1745-b1f8-4fa9-9d96-b0ec9934cbbd\"}\n[2026-05-11 10:17:42] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610915,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f131d63b-7da9-4a0c-b9d5-4a2d2ae772f1\"}\n[2026-05-11 10:17:42] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610915} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f131d63b-7da9-4a0c-b9d5-4a2d2ae772f1\"}\n[2026-05-11 10:17:42] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610915,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f131d63b-7da9-4a0c-b9d5-4a2d2ae772f1\"}\n[2026-05-11 10:17:42] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610915,\"participants\":[{\"id\":997104,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997105,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f131d63b-7da9-4a0c-b9d5-4a2d2ae772f1\"}\n[2026-05-11 10:17:42] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f131d63b-7da9-4a0c-b9d5-4a2d2ae772f1\"}\n[2026-05-11 10:17:42] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f131d63b-7da9-4a0c-b9d5-4a2d2ae772f1\"}\n[2026-05-11 10:17:42] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f131d63b-7da9-4a0c-b9d5-4a2d2ae772f1\"}\n[2026-05-11 10:17:42] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f131d63b-7da9-4a0c-b9d5-4a2d2ae772f1\"}\n[2026-05-11 10:17:42] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f131d63b-7da9-4a0c-b9d5-4a2d2ae772f1\"}\n[2026-05-11 10:17:42] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f131d63b-7da9-4a0c-b9d5-4a2d2ae772f1\"}\n[2026-05-11 10:17:42] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":11} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f131d63b-7da9-4a0c-b9d5-4a2d2ae772f1\"}\n[2026-05-11 10:17:42] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610764,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"93d7f7d1-3a5c-47ce-bc42-1af98a032e7b\"}\n[2026-05-11 10:17:42] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610764} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"93d7f7d1-3a5c-47ce-bc42-1af98a032e7b\"}\n[2026-05-11 10:17:42] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610764,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"93d7f7d1-3a5c-47ce-bc42-1af98a032e7b\"}\n[2026-05-11 10:17:42] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610764,\"participants\":[{\"id\":996951,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996952,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"93d7f7d1-3a5c-47ce-bc42-1af98a032e7b\"}\n[2026-05-11 10:17:42] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"93d7f7d1-3a5c-47ce-bc42-1af98a032e7b\"}\n[2026-05-11 10:17:42] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"93d7f7d1-3a5c-47ce-bc42-1af98a032e7b\"}\n[2026-05-11 10:17:42] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"93d7f7d1-3a5c-47ce-bc42-1af98a032e7b\"}\n[2026-05-11 10:17:42] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"93d7f7d1-3a5c-47ce-bc42-1af98a032e7b\"}\n[2026-05-11 10:17:42] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"93d7f7d1-3a5c-47ce-bc42-1af98a032e7b\"}\n[2026-05-11 10:17:42] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"93d7f7d1-3a5c-47ce-bc42-1af98a032e7b\"}\n[2026-05-11 10:17:42] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":15} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"93d7f7d1-3a5c-47ce-bc42-1af98a032e7b\"}\n[2026-05-11 10:17:42] local.INFO: [ EsUpdateProcessManager ] Finished updating entities in ES {\"worker\":\"\",\"peak_memory\":\"99.73 MB\",\"elapsed_seconds\":0.23,\"update_target\":\"activities\",\"should_iterate_again\":false} {\"correlation_id\":\"4ad05333-9afb-492e-9f0f-b2909ac45b32\",\"trace_id\":\"3d8feb24-b173-4158-b0a4-4cf33af85066\"}\n[2026-05-11 10:17:43] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610490,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"efb63783-8dfd-4c44-805a-c36bcb5e317e\"}\n[2026-05-11 10:17:43] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610490} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"efb63783-8dfd-4c44-805a-c36bcb5e317e\"}\n[2026-05-11 10:17:43] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610490,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"efb63783-8dfd-4c44-805a-c36bcb5e317e\"}\n[2026-05-11 10:17:43] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610490,\"participants\":[{\"id\":996385,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996386,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"efb63783-8dfd-4c44-805a-c36bcb5e317e\"}\n[2026-05-11 10:17:43] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"efb63783-8dfd-4c44-805a-c36bcb5e317e\"}\n[2026-05-11 10:17:43] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"efb63783-8dfd-4c44-805a-c36bcb5e317e\"}\n[2026-05-11 10:17:43] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"efb63783-8dfd-4c44-805a-c36bcb5e317e\"}\n[2026-05-11 10:17:43] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"efb63783-8dfd-4c44-805a-c36bcb5e317e\"}\n[2026-05-11 10:17:43] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"efb63783-8dfd-4c44-805a-c36bcb5e317e\"}\n[2026-05-11 10:17:43] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"efb63783-8dfd-4c44-805a-c36bcb5e317e\"}\n[2026-05-11 10:17:43] local.WARNING: [Hubspot] No retry-after header or policy name found, using default {\"exception_class\":\"SevenShores\\\\Hubspot\\\\Exceptions\\\\BadRequest\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"efb63783-8dfd-4c44-805a-c36bcb5e317e\"}\n[2026-05-11 10:17:43] local.WARNING: [Hubspot] Received 429 from API {\"team_id\":2,\"config_id\":2,\"retry_after\":10,\"policy\":null,\"reason\":\"Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response:\n{\\\"status\\\":\\\"error\\\",\\\"message\\\":\\\"You have reached your secondly limit.\\\",\\\"errorType\\\":\\\"RATE_LIMIT\\\",\\\"correlationId\\\":\\\"019e168a-e (truncated...)\n\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"efb63783-8dfd-4c44-805a-c36bcb5e317e\"}\n[2026-05-11 10:17:43] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":14} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"efb63783-8dfd-4c44-805a-c36bcb5e317e\"}\n[2026-05-11 10:17:43] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610528,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"34f22bc6-50a7-4f6e-96be-552d05a23255\"}\n[2026-05-11 10:17:43] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610528} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"34f22bc6-50a7-4f6e-96be-552d05a23255\"}\n[2026-05-11 10:17:43] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610528,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"34f22bc6-50a7-4f6e-96be-552d05a23255\"}\n[2026-05-11 10:17:43] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610528,\"participants\":[{\"id\":996463,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996464,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"34f22bc6-50a7-4f6e-96be-552d05a23255\"}\n[2026-05-11 10:17:43] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"34f22bc6-50a7-4f6e-96be-552d05a23255\"}\n[2026-05-11 10:17:43] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"34f22bc6-50a7-4f6e-96be-552d05a23255\"}\n[2026-05-11 10:17:43] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"34f22bc6-50a7-4f6e-96be-552d05a23255\"}\n[2026-05-11 10:17:43] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"34f22bc6-50a7-4f6e-96be-552d05a23255\"}\n[2026-05-11 10:17:43] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"34f22bc6-50a7-4f6e-96be-552d05a23255\"}\n[2026-05-11 10:17:43] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"34f22bc6-50a7-4f6e-96be-552d05a23255\"}\n[2026-05-11 10:17:43] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":11} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"34f22bc6-50a7-4f6e-96be-552d05a23255\"}\n[2026-05-11 10:17:43] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610885,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"624ce203-96d1-4009-ae4e-5b6635eff4b0\"}\n[2026-05-11 10:17:43] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610885} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"624ce203-96d1-4009-ae4e-5b6635eff4b0\"}\n[2026-05-11 10:17:43] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610885,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"624ce203-96d1-4009-ae4e-5b6635eff4b0\"}\n[2026-05-11 10:17:43] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610885,\"participants\":[{\"id\":997051,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997052,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"624ce203-96d1-4009-ae4e-5b6635eff4b0\"}\n[2026-05-11 10:17:43] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"624ce203-96d1-4009-ae4e-5b6635eff4b0\"}\n[2026-05-11 10:17:43] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"624ce203-96d1-4009-ae4e-5b6635eff4b0\"}\n[2026-05-11 10:17:43] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"624ce203-96d1-4009-ae4e-5b6635eff4b0\"}\n[2026-05-11 10:17:43] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"624ce203-96d1-4009-ae4e-5b6635eff4b0\"}\n[2026-05-11 10:17:43] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"624ce203-96d1-4009-ae4e-5b6635eff4b0\"}\n[2026-05-11 10:17:43] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"624ce203-96d1-4009-ae4e-5b6635eff4b0\"}\n[2026-05-11 10:17:43] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":12} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"624ce203-96d1-4009-ae4e-5b6635eff4b0\"}\n[2026-05-11 10:17:44] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610451,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"99d1cf07-a91d-4a90-8059-1fe54fb6097a\"}\n[2026-05-11 10:17:44] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610451} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"99d1cf07-a91d-4a90-8059-1fe54fb6097a\"}\n[2026-05-11 10:17:44] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610451,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"99d1cf07-a91d-4a90-8059-1fe54fb6097a\"}\n[2026-05-11 10:17:44] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610451,\"participants\":[{\"id\":996340,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996341,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"99d1cf07-a91d-4a90-8059-1fe54fb6097a\"}\n[2026-05-11 10:17:44] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"99d1cf07-a91d-4a90-8059-1fe54fb6097a\"}\n[2026-05-11 10:17:44] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"99d1cf07-a91d-4a90-8059-1fe54fb6097a\"}\n[2026-05-11 10:17:44] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"99d1cf07-a91d-4a90-8059-1fe54fb6097a\"}\n[2026-05-11 10:17:44] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"99d1cf07-a91d-4a90-8059-1fe54fb6097a\"}\n[2026-05-11 10:17:44] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"99d1cf07-a91d-4a90-8059-1fe54fb6097a\"}\n[2026-05-11 10:17:44] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"99d1cf07-a91d-4a90-8059-1fe54fb6097a\"}\n[2026-05-11 10:17:44] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":13} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"99d1cf07-a91d-4a90-8059-1fe54fb6097a\"}\n[2026-05-11 10:17:44] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614381,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"71db6557-d1a4-488a-bcaa-cefeb41f9f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614381} {\"correlation_id\":\"71db6557-d1a4-488a-bcaa-cefeb41f9f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614381,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"71db6557-d1a4-488a-bcaa-cefeb41f9f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614381,\"participants\":[{\"id\":1002630,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002631,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"71db6557-d1a4-488a-bcaa-cefeb41f9f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"71db6557-d1a4-488a-bcaa-cefeb41f9f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"71db6557-d1a4-488a-bcaa-cefeb41f9f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"71db6557-d1a4-488a-bcaa-cefeb41f9f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"71db6557-d1a4-488a-bcaa-cefeb41f9f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"71db6557-d1a4-488a-bcaa-cefeb41f9f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"71db6557-d1a4-488a-bcaa-cefeb41f9f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":13} {\"correlation_id\":\"71db6557-d1a4-488a-bcaa-cefeb41f9f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610874,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"c4fcf2aa-0846-4e80-b18b-251b2d368949\"}\n[2026-05-11 10:17:44] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610874} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"c4fcf2aa-0846-4e80-b18b-251b2d368949\"}\n[2026-05-11 10:17:44] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610874,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"c4fcf2aa-0846-4e80-b18b-251b2d368949\"}\n[2026-05-11 10:17:44] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610874,\"participants\":[{\"id\":997025,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997026,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"c4fcf2aa-0846-4e80-b18b-251b2d368949\"}\n[2026-05-11 10:17:44] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"c4fcf2aa-0846-4e80-b18b-251b2d368949\"}\n[2026-05-11 10:17:44] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"c4fcf2aa-0846-4e80-b18b-251b2d368949\"}\n[2026-05-11 10:17:44] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"c4fcf2aa-0846-4e80-b18b-251b2d368949\"}\n[2026-05-11 10:17:44] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"c4fcf2aa-0846-4e80-b18b-251b2d368949\"}\n[2026-05-11 10:17:44] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"c4fcf2aa-0846-4e80-b18b-251b2d368949\"}\n[2026-05-11 10:17:44] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"c4fcf2aa-0846-4e80-b18b-251b2d368949\"}\n[2026-05-11 10:17:44] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":10} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"c4fcf2aa-0846-4e80-b18b-251b2d368949\"}\n[2026-05-11 10:17:44] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612560,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"286a6558-1e66-4ffb-b32f-9f823a296d14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612560} {\"correlation_id\":\"286a6558-1e66-4ffb-b32f-9f823a296d14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612560,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"286a6558-1e66-4ffb-b32f-9f823a296d14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612560,\"participants\":[{\"id\":999778,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999779,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"286a6558-1e66-4ffb-b32f-9f823a296d14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"286a6558-1e66-4ffb-b32f-9f823a296d14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"286a6558-1e66-4ffb-b32f-9f823a296d14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"286a6558-1e66-4ffb-b32f-9f823a296d14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"286a6558-1e66-4ffb-b32f-9f823a296d14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"correlation_id\":\"286a6558-1e66-4ffb-b32f-9f823a296d14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"447782589921@txt.staging.jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/447782589921%40txt.staging.jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"correlation_id\":\"286a6558-1e66-4ffb-b32f-9f823a296d14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"correlation_id\":\"286a6558-1e66-4ffb-b32f-9f823a296d14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":15} {\"correlation_id\":\"286a6558-1e66-4ffb-b32f-9f823a296d14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614382,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"c0afdc10-8cad-4dab-9147-5495fc19b7c4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614382} {\"correlation_id\":\"c0afdc10-8cad-4dab-9147-5495fc19b7c4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614382,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"c0afdc10-8cad-4dab-9147-5495fc19b7c4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614382,\"participants\":[{\"id\":1002632,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002633,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"c0afdc10-8cad-4dab-9147-5495fc19b7c4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"c0afdc10-8cad-4dab-9147-5495fc19b7c4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"c0afdc10-8cad-4dab-9147-5495fc19b7c4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"c0afdc10-8cad-4dab-9147-5495fc19b7c4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"c0afdc10-8cad-4dab-9147-5495fc19b7c4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"c0afdc10-8cad-4dab-9147-5495fc19b7c4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"c0afdc10-8cad-4dab-9147-5495fc19b7c4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":12} {\"correlation_id\":\"c0afdc10-8cad-4dab-9147-5495fc19b7c4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610867,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1b88706b-8ac4-431d-8696-8f8766ecae33\"}\n[2026-05-11 10:17:45] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610867} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1b88706b-8ac4-431d-8696-8f8766ecae33\"}\n[2026-05-11 10:17:45] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610867,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1b88706b-8ac4-431d-8696-8f8766ecae33\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610867,\"participants\":[{\"id\":997011,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997012,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1b88706b-8ac4-431d-8696-8f8766ecae33\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1b88706b-8ac4-431d-8696-8f8766ecae33\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1b88706b-8ac4-431d-8696-8f8766ecae33\"}\n[2026-05-11 10:17:45] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1b88706b-8ac4-431d-8696-8f8766ecae33\"}\n[2026-05-11 10:17:45] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1b88706b-8ac4-431d-8696-8f8766ecae33\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1b88706b-8ac4-431d-8696-8f8766ecae33\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1b88706b-8ac4-431d-8696-8f8766ecae33\"}\n[2026-05-11 10:17:45] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":11} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1b88706b-8ac4-431d-8696-8f8766ecae33\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612819,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612819} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612819,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612819,\"participants\":[{\"id\":1000073,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1000074,\"user_id\":261,\"contact_id\":null,\"lead_id\":null},{\"id\":1000075,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: ProspectCache - Searching DB for opportunity by owner {\"account_id\":244,\"contact_id\":4487,\"owner_id\":261} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: ProspectCache - Opportunity DB search results {\"account_id\":244,\"contact_id\":4487,\"opportunity_id\":299} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612819,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"adelina.petrova@jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/adelina.petrova%40jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":15} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612847,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"b4c629ce-833d-484c-8155-4df866fe54cf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612847} {\"correlation_id\":\"b4c629ce-833d-484c-8155-4df866fe54cf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612847,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"b4c629ce-833d-484c-8155-4df866fe54cf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612847,\"participants\":[{\"id\":1000130,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1000131,\"user_id\":261,\"contact_id\":null,\"lead_id\":null},{\"id\":1000151,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null}]} {\"correlation_id\":\"b4c629ce-833d-484c-8155-4df866fe54cf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b4c629ce-833d-484c-8155-4df866fe54cf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b4c629ce-833d-484c-8155-4df866fe54cf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"b4c629ce-833d-484c-8155-4df866fe54cf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"b4c629ce-833d-484c-8155-4df866fe54cf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"correlation_id\":\"b4c629ce-833d-484c-8155-4df866fe54cf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"correlation_id\":\"b4c629ce-833d-484c-8155-4df866fe54cf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":15} {\"correlation_id\":\"b4c629ce-833d-484c-8155-4df866fe54cf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610506,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"168d2aac-7bb8-4249-b62a-e088ef05a5c3\"}\n[2026-05-11 10:17:45] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610506} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"168d2aac-7bb8-4249-b62a-e088ef05a5c3\"}\n[2026-05-11 10:17:45] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610506,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"168d2aac-7bb8-4249-b62a-e088ef05a5c3\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610506,\"participants\":[{\"id\":996419,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996420,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"168d2aac-7bb8-4249-b62a-e088ef05a5c3\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"168d2aac-7bb8-4249-b62a-e088ef05a5c3\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"168d2aac-7bb8-4249-b62a-e088ef05a5c3\"}\n[2026-05-11 10:17:45] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"168d2aac-7bb8-4249-b62a-e088ef05a5c3\"}\n[2026-05-11 10:17:45] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"168d2aac-7bb8-4249-b62a-e088ef05a5c3\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"168d2aac-7bb8-4249-b62a-e088ef05a5c3\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"168d2aac-7bb8-4249-b62a-e088ef05a5c3\"}\n[2026-05-11 10:17:45] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":12} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"168d2aac-7bb8-4249-b62a-e088ef05a5c3\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610497,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"067b89fc-5453-49ae-a3fa-5dfdb487c294\"}\n[2026-05-11 10:17:45] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610497} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"067b89fc-5453-49ae-a3fa-5dfdb487c294\"}\n[2026-05-11 10:17:45] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610497,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"067b89fc-5453-49ae-a3fa-5dfdb487c294\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610497,\"participants\":[{\"id\":996401,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996402,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"067b89fc-5453-49ae-a3fa-5dfdb487c294\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"067b89fc-5453-49ae-a3fa-5dfdb487c294\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"067b89fc-5453-49ae-a3fa-5dfdb487c294\"}\n[2026-05-11 10:17:45] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"067b89fc-5453-49ae-a3fa-5dfdb487c294\"}\n[2026-05-11 10:17:45] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"067b89fc-5453-49ae-a3fa-5dfdb487c294\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"067b89fc-5453-49ae-a3fa-5dfdb487c294\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"067b89fc-5453-49ae-a3fa-5dfdb487c294\"}\n[2026-05-11 10:17:45] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":10} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"067b89fc-5453-49ae-a3fa-5dfdb487c294\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610617,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e2d3538d-9a14-45c4-b068-84b3732061df\"}\n[2026-05-11 10:17:45] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610617} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e2d3538d-9a14-45c4-b068-84b3732061df\"}\n[2026-05-11 10:17:45] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610617,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e2d3538d-9a14-45c4-b068-84b3732061df\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610617,\"participants\":[{\"id\":996641,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996642,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e2d3538d-9a14-45c4-b068-84b3732061df\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e2d3538d-9a14-45c4-b068-84b3732061df\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e2d3538d-9a14-45c4-b068-84b3732061df\"}\n[2026-05-11 10:17:45] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e2d3538d-9a14-45c4-b068-84b3732061df\"}\n[2026-05-11 10:17:45] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e2d3538d-9a14-45c4-b068-84b3732061df\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e2d3538d-9a14-45c4-b068-84b3732061df\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e2d3538d-9a14-45c4-b068-84b3732061df\"}\n[2026-05-11 10:17:45] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":10} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e2d3538d-9a14-45c4-b068-84b3732061df\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610403,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e7285c6c-728d-4284-b885-7e9e9df72706\"}\n[2026-05-11 10:17:45] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610403} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e7285c6c-728d-4284-b885-7e9e9df72706\"}\n[2026-05-11 10:17:45] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610403,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e7285c6c-728d-4284-b885-7e9e9df72706\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610403,\"participants\":[{\"id\":996282,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996283,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e7285c6c-728d-4284-b885-7e9e9df72706\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e7285c6c-728d-4284-b885-7e9e9df72706\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e7285c6c-728d-4284-b885-7e9e9df72706\"}\n[2026-05-11 10:17:45] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e7285c6c-728d-4284-b885-7e9e9df72706\"}\n[2026-05-11 10:17:45] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e7285c6c-728d-4284-b885-7e9e9df72706\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e7285c6c-728d-4284-b885-7e9e9df72706\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e7285c6c-728d-4284-b885-7e9e9df72706\"}\n[2026-05-11 10:17:45] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":12} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e7285c6c-728d-4284-b885-7e9e9df72706\"}\n[2026-05-11 10:17:46] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614378,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":6167,\"account_id\":null,\"opportunity_id\":null,\"stage_id\":null}} {\"correlation_id\":\"5463b5ad-2286-4568-8f68-76b82d8a4c54\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:46] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614378} {\"correlation_id\":\"5463b5ad-2286-4568-8f68-76b82d8a4c54\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:46] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614378,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"5463b5ad-2286-4568-8f68-76b82d8a4c54\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:46] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614378,\"participants\":[{\"id\":1002623,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002624,\"user_id\":null,\"contact_id\":6167,\"lead_id\":null},{\"id\":1002625,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"5463b5ad-2286-4568-8f68-76b82d8a4c54\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:46] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"5463b5ad-2286-4568-8f68-76b82d8a4c54\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:46] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"5463b5ad-2286-4568-8f68-76b82d8a4c54\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:46] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"5463b5ad-2286-4568-8f68-76b82d8a4c54\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:46] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"5463b5ad-2286-4568-8f68-76b82d8a4c54\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:46] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"5463b5ad-2286-4568-8f68-76b82d8a4c54\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:46] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"5463b5ad-2286-4568-8f68-76b82d8a4c54\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":15} {\"correlation_id\":\"5463b5ad-2286-4568-8f68-76b82d8a4c54\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612561,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"ca6930a0-aebc-4338-856e-6a439a838639\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612561} {\"correlation_id\":\"ca6930a0-aebc-4338-856e-6a439a838639\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612561,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"ca6930a0-aebc-4338-856e-6a439a838639\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612561,\"participants\":[{\"id\":999780,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999781,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"ca6930a0-aebc-4338-856e-6a439a838639\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"ca6930a0-aebc-4338-856e-6a439a838639\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"ca6930a0-aebc-4338-856e-6a439a838639\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"ca6930a0-aebc-4338-856e-6a439a838639\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"ca6930a0-aebc-4338-856e-6a439a838639\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612561,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"ca6930a0-aebc-4338-856e-6a439a838639\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"447700174614.447782589921.OeREojLVnk@txt.staging.jiminny.com\"} {\"correlation_id\":\"ca6930a0-aebc-4338-856e-6a439a838639\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"447700174614.447782589921.OeREojLVnk@txt.staging.jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/447700174614.447782589921.OeREojLVnk%40txt.staging.jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"correlation_id\":\"ca6930a0-aebc-4338-856e-6a439a838639\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"447700174614.447782589921.OeREojLVnk@txt.staging.jiminny.com\"} {\"correlation_id\":\"ca6930a0-aebc-4338-856e-6a439a838639\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"ca6930a0-aebc-4338-856e-6a439a838639\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610438,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7721c535-7311-417a-b30a-1286a84e037b\"}\n[2026-05-11 10:17:47] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610438} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7721c535-7311-417a-b30a-1286a84e037b\"}\n[2026-05-11 10:17:47] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610438,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7721c535-7311-417a-b30a-1286a84e037b\"}\n[2026-05-11 10:17:47] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610438,\"participants\":[{\"id\":996320,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996321,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7721c535-7311-417a-b30a-1286a84e037b\"}\n[2026-05-11 10:17:47] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7721c535-7311-417a-b30a-1286a84e037b\"}\n[2026-05-11 10:17:47] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7721c535-7311-417a-b30a-1286a84e037b\"}\n[2026-05-11 10:17:47] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7721c535-7311-417a-b30a-1286a84e037b\"}\n[2026-05-11 10:17:47] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7721c535-7311-417a-b30a-1286a84e037b\"}\n[2026-05-11 10:17:47] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7721c535-7311-417a-b30a-1286a84e037b\"}\n[2026-05-11 10:17:47] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7721c535-7311-417a-b30a-1286a84e037b\"}\n[2026-05-11 10:17:47] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":12} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7721c535-7311-417a-b30a-1286a84e037b\"}\n[2026-05-11 10:17:47] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614436,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"e20af459-b149-4a19-8ef6-4444b4cee8f9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614436} {\"correlation_id\":\"e20af459-b149-4a19-8ef6-4444b4cee8f9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614436,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"e20af459-b149-4a19-8ef6-4444b4cee8f9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614436,\"participants\":[{\"id\":1002751,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002752,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"e20af459-b149-4a19-8ef6-4444b4cee8f9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"e20af459-b149-4a19-8ef6-4444b4cee8f9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"e20af459-b149-4a19-8ef6-4444b4cee8f9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"e20af459-b149-4a19-8ef6-4444b4cee8f9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"e20af459-b149-4a19-8ef6-4444b4cee8f9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"e20af459-b149-4a19-8ef6-4444b4cee8f9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"e20af459-b149-4a19-8ef6-4444b4cee8f9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"e20af459-b149-4a19-8ef6-4444b4cee8f9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610462,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90f3fc25-e34d-4c3a-b35c-84317a633c78\"}\n[2026-05-11 10:17:47] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610462} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90f3fc25-e34d-4c3a-b35c-84317a633c78\"}\n[2026-05-11 10:17:47] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610462,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90f3fc25-e34d-4c3a-b35c-84317a633c78\"}\n[2026-05-11 10:17:47] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610462,\"participants\":[{\"id\":996353,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996354,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90f3fc25-e34d-4c3a-b35c-84317a633c78\"}\n[2026-05-11 10:17:47] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90f3fc25-e34d-4c3a-b35c-84317a633c78\"}\n[2026-05-11 10:17:47] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90f3fc25-e34d-4c3a-b35c-84317a633c78\"}\n[2026-05-11 10:17:47] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90f3fc25-e34d-4c3a-b35c-84317a633c78\"}\n[2026-05-11 10:17:47] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90f3fc25-e34d-4c3a-b35c-84317a633c78\"}\n[2026-05-11 10:17:47] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90f3fc25-e34d-4c3a-b35c-84317a633c78\"}\n[2026-05-11 10:17:47] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90f3fc25-e34d-4c3a-b35c-84317a633c78\"}\n[2026-05-11 10:17:47] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":14} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90f3fc25-e34d-4c3a-b35c-84317a633c78\"}\n[2026-05-11 10:17:47] local.INFO: [ EsUpdateProcessManager ] Finished updating entities in ES {\"worker\":\"\",\"peak_memory\":\"99.73 MB\",\"elapsed_seconds\":0.21,\"update_target\":\"activities\",\"should_iterate_again\":false} {\"correlation_id\":\"4ad05333-9afb-492e-9f0f-b2909ac45b32\",\"trace_id\":\"3d8feb24-b173-4158-b0a4-4cf33af85066\"}\n[2026-05-11 10:17:48] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610470,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6264c9dd-ba42-4c8f-a21f-3dffeb0c31c6\"}\n[2026-05-11 10:17:48] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610470} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6264c9dd-ba42-4c8f-a21f-3dffeb0c31c6\"}\n[2026-05-11 10:17:48] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610470,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6264c9dd-ba42-4c8f-a21f-3dffeb0c31c6\"}\n[2026-05-11 10:17:48] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610470,\"participants\":[{\"id\":996369,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996370,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6264c9dd-ba42-4c8f-a21f-3dffeb0c31c6\"}\n[2026-05-11 10:17:48] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6264c9dd-ba42-4c8f-a21f-3dffeb0c31c6\"}\n[2026-05-11 10:17:48] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6264c9dd-ba42-4c8f-a21f-3dffeb0c31c6\"}\n[2026-05-11 10:17:48] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6264c9dd-ba42-4c8f-a21f-3dffeb0c31c6\"}\n[2026-05-11 10:17:48] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6264c9dd-ba42-4c8f-a21f-3dffeb0c31c6\"}\n[2026-05-11 10:17:48] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6264c9dd-ba42-4c8f-a21f-3dffeb0c31c6\"}\n[2026-05-11 10:17:48] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6264c9dd-ba42-4c8f-a21f-3dffeb0c31c6\"}\n[2026-05-11 10:17:48] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":12} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6264c9dd-ba42-4c8f-a21f-3dffeb0c31c6\"}\n[2026-05-11 10:17:48] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":615092,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"64b7efd5-f92f-42b8-95ba-9a9e76fbb676\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":615092} {\"correlation_id\":\"64b7efd5-f92f-42b8-95ba-9a9e76fbb676\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":615092,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"64b7efd5-f92f-42b8-95ba-9a9e76fbb676\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":615092,\"participants\":[{\"id\":1004102,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1004103,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"64b7efd5-f92f-42b8-95ba-9a9e76fbb676\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"64b7efd5-f92f-42b8-95ba-9a9e76fbb676\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"64b7efd5-f92f-42b8-95ba-9a9e76fbb676\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"64b7efd5-f92f-42b8-95ba-9a9e76fbb676\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"64b7efd5-f92f-42b8-95ba-9a9e76fbb676\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"64b7efd5-f92f-42b8-95ba-9a9e76fbb676\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"64b7efd5-f92f-42b8-95ba-9a9e76fbb676\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"64b7efd5-f92f-42b8-95ba-9a9e76fbb676\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612562,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"aa8720ba-c5e3-4d7e-a7c3-697da34a195e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612562} {\"correlation_id\":\"aa8720ba-c5e3-4d7e-a7c3-697da34a195e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612562,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"aa8720ba-c5e3-4d7e-a7c3-697da34a195e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612562,\"participants\":[{\"id\":999782,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999783,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"aa8720ba-c5e3-4d7e-a7c3-697da34a195e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"aa8720ba-c5e3-4d7e-a7c3-697da34a195e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"aa8720ba-c5e3-4d7e-a7c3-697da34a195e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"aa8720ba-c5e3-4d7e-a7c3-697da34a195e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"aa8720ba-c5e3-4d7e-a7c3-697da34a195e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"correlation_id\":\"aa8720ba-c5e3-4d7e-a7c3-697da34a195e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"correlation_id\":\"aa8720ba-c5e3-4d7e-a7c3-697da34a195e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"aa8720ba-c5e3-4d7e-a7c3-697da34a195e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610900,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"1abedcde-ca97-4113-b4a6-60a45a16f9d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610900} {\"correlation_id\":\"1abedcde-ca97-4113-b4a6-60a45a16f9d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610900,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"1abedcde-ca97-4113-b4a6-60a45a16f9d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610900,\"participants\":[{\"id\":997081,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997082,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"1abedcde-ca97-4113-b4a6-60a45a16f9d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"1abedcde-ca97-4113-b4a6-60a45a16f9d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"1abedcde-ca97-4113-b4a6-60a45a16f9d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"1abedcde-ca97-4113-b4a6-60a45a16f9d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"1abedcde-ca97-4113-b4a6-60a45a16f9d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"1abedcde-ca97-4113-b4a6-60a45a16f9d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"1abedcde-ca97-4113-b4a6-60a45a16f9d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":12} {\"correlation_id\":\"1abedcde-ca97-4113-b4a6-60a45a16f9d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610935,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"d4390ffe-1359-41f6-9feb-f0bfbfdafc61\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610935} {\"correlation_id\":\"d4390ffe-1359-41f6-9feb-f0bfbfdafc61\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610935,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"d4390ffe-1359-41f6-9feb-f0bfbfdafc61\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610935,\"participants\":[{\"id\":997141,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997142,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"d4390ffe-1359-41f6-9feb-f0bfbfdafc61\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"d4390ffe-1359-41f6-9feb-f0bfbfdafc61\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"d4390ffe-1359-41f6-9feb-f0bfbfdafc61\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"d4390ffe-1359-41f6-9feb-f0bfbfdafc61\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"d4390ffe-1359-41f6-9feb-f0bfbfdafc61\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"d4390ffe-1359-41f6-9feb-f0bfbfdafc61\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"d4390ffe-1359-41f6-9feb-f0bfbfdafc61\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":12} {\"correlation_id\":\"d4390ffe-1359-41f6-9feb-f0bfbfdafc61\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611451,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"42a128d7-d841-4c03-a6c0-7b9fa918ec1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611451} {\"correlation_id\":\"42a128d7-d841-4c03-a6c0-7b9fa918ec1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611451,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"42a128d7-d841-4c03-a6c0-7b9fa918ec1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611451,\"participants\":[{\"id\":997955,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997956,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"42a128d7-d841-4c03-a6c0-7b9fa918ec1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"42a128d7-d841-4c03-a6c0-7b9fa918ec1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"42a128d7-d841-4c03-a6c0-7b9fa918ec1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"42a128d7-d841-4c03-a6c0-7b9fa918ec1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"42a128d7-d841-4c03-a6c0-7b9fa918ec1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"42a128d7-d841-4c03-a6c0-7b9fa918ec1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"42a128d7-d841-4c03-a6c0-7b9fa918ec1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"42a128d7-d841-4c03-a6c0-7b9fa918ec1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612340,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"68eaf196-29ca-48a3-8e46-5bf37620dd08\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612340} {\"correlation_id\":\"68eaf196-29ca-48a3-8e46-5bf37620dd08\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612340,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"68eaf196-29ca-48a3-8e46-5bf37620dd08\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612340,\"participants\":[{\"id\":999516,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999517,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999518,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999519,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"68eaf196-29ca-48a3-8e46-5bf37620dd08\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"68eaf196-29ca-48a3-8e46-5bf37620dd08\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"68eaf196-29ca-48a3-8e46-5bf37620dd08\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"68eaf196-29ca-48a3-8e46-5bf37620dd08\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"68eaf196-29ca-48a3-8e46-5bf37620dd08\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"68eaf196-29ca-48a3-8e46-5bf37620dd08\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612340,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"68eaf196-29ca-48a3-8e46-5bf37620dd08\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":15} {\"correlation_id\":\"68eaf196-29ca-48a3-8e46-5bf37620dd08\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610426,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f997c306-a176-4f3a-8699-d9cd083d6993\"}\n[2026-05-11 10:17:49] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610426} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f997c306-a176-4f3a-8699-d9cd083d6993\"}\n[2026-05-11 10:17:49] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610426,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f997c306-a176-4f3a-8699-d9cd083d6993\"}\n[2026-05-11 10:17:49] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610426,\"participants\":[{\"id\":996306,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996307,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f997c306-a176-4f3a-8699-d9cd083d6993\"}\n[2026-05-11 10:17:49] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f997c306-a176-4f3a-8699-d9cd083d6993\"}\n[2026-05-11 10:17:49] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f997c306-a176-4f3a-8699-d9cd083d6993\"}\n[2026-05-11 10:17:49] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f997c306-a176-4f3a-8699-d9cd083d6993\"}\n[2026-05-11 10:17:49] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f997c306-a176-4f3a-8699-d9cd083d6993\"}\n[2026-05-11 10:17:49] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f997c306-a176-4f3a-8699-d9cd083d6993\"}\n[2026-05-11 10:17:49] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f997c306-a176-4f3a-8699-d9cd083d6993\"}\n[2026-05-11 10:17:49] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":11} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f997c306-a176-4f3a-8699-d9cd083d6993\"}\n[2026-05-11 10:17:49] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612336,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"18efa24c-257e-4842-af7d-5ec20872ab02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612336} {\"correlation_id\":\"18efa24c-257e-4842-af7d-5ec20872ab02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612336,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"18efa24c-257e-4842-af7d-5ec20872ab02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612336,\"participants\":[{\"id\":999508,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999509,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999512,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999513,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"18efa24c-257e-4842-af7d-5ec20872ab02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"18efa24c-257e-4842-af7d-5ec20872ab02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"18efa24c-257e-4842-af7d-5ec20872ab02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"18efa24c-257e-4842-af7d-5ec20872ab02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"18efa24c-257e-4842-af7d-5ec20872ab02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"18efa24c-257e-4842-af7d-5ec20872ab02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612336,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"18efa24c-257e-4842-af7d-5ec20872ab02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"18efa24c-257e-4842-af7d-5ec20872ab02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612360,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"af4fe4e8-53c1-4339-8100-49dadac0f280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612360} {\"correlation_id\":\"af4fe4e8-53c1-4339-8100-49dadac0f280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612360,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"af4fe4e8-53c1-4339-8100-49dadac0f280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612360,\"participants\":[{\"id\":999552,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999553,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999565,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"af4fe4e8-53c1-4339-8100-49dadac0f280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"af4fe4e8-53c1-4339-8100-49dadac0f280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"af4fe4e8-53c1-4339-8100-49dadac0f280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"af4fe4e8-53c1-4339-8100-49dadac0f280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"af4fe4e8-53c1-4339-8100-49dadac0f280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"af4fe4e8-53c1-4339-8100-49dadac0f280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612360,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"af4fe4e8-53c1-4339-8100-49dadac0f280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":13} {\"correlation_id\":\"af4fe4e8-53c1-4339-8100-49dadac0f280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612339,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"68a001e2-a116-4b5d-b8e7-902d08ada842\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612339} {\"correlation_id\":\"68a001e2-a116-4b5d-b8e7-902d08ada842\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612339,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"68a001e2-a116-4b5d-b8e7-902d08ada842\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612339,\"participants\":[{\"id\":999514,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999515,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999540,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"68a001e2-a116-4b5d-b8e7-902d08ada842\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"68a001e2-a116-4b5d-b8e7-902d08ada842\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"68a001e2-a116-4b5d-b8e7-902d08ada842\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"68a001e2-a116-4b5d-b8e7-902d08ada842\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"68a001e2-a116-4b5d-b8e7-902d08ada842\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"68a001e2-a116-4b5d-b8e7-902d08ada842\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612339,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"68a001e2-a116-4b5d-b8e7-902d08ada842\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":13} {\"correlation_id\":\"68a001e2-a116-4b5d-b8e7-902d08ada842\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611087,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"19bb8a09-8a89-4524-bfc1-e972923a1f2b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611087} {\"correlation_id\":\"19bb8a09-8a89-4524-bfc1-e972923a1f2b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611087,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"19bb8a09-8a89-4524-bfc1-e972923a1f2b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611087,\"participants\":[{\"id\":997368,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997369,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"19bb8a09-8a89-4524-bfc1-e972923a1f2b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"19bb8a09-8a89-4524-bfc1-e972923a1f2b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"19bb8a09-8a89-4524-bfc1-e972923a1f2b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"19bb8a09-8a89-4524-bfc1-e972923a1f2b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"19bb8a09-8a89-4524-bfc1-e972923a1f2b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"19bb8a09-8a89-4524-bfc1-e972923a1f2b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"19bb8a09-8a89-4524-bfc1-e972923a1f2b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":15} {\"correlation_id\":\"19bb8a09-8a89-4524-bfc1-e972923a1f2b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611455,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"dd53be6e-a456-46da-ab7c-c2988301922f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611455} {\"correlation_id\":\"dd53be6e-a456-46da-ab7c-c2988301922f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611455,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"dd53be6e-a456-46da-ab7c-c2988301922f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611455,\"participants\":[{\"id\":997961,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997962,\"user_id\":1460,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"dd53be6e-a456-46da-ab7c-c2988301922f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"dd53be6e-a456-46da-ab7c-c2988301922f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"dd53be6e-a456-46da-ab7c-c2988301922f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"dd53be6e-a456-46da-ab7c-c2988301922f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"dd53be6e-a456-46da-ab7c-c2988301922f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"dd53be6e-a456-46da-ab7c-c2988301922f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"dd53be6e-a456-46da-ab7c-c2988301922f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":13} {\"correlation_id\":\"dd53be6e-a456-46da-ab7c-c2988301922f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611076,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"4d0438c5-9dc4-4b93-b643-6417ac75f31a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611076} {\"correlation_id\":\"4d0438c5-9dc4-4b93-b643-6417ac75f31a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611076,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"4d0438c5-9dc4-4b93-b643-6417ac75f31a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611076,\"participants\":[{\"id\":997346,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997347,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"4d0438c5-9dc4-4b93-b643-6417ac75f31a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4d0438c5-9dc4-4b93-b643-6417ac75f31a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4d0438c5-9dc4-4b93-b643-6417ac75f31a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"4d0438c5-9dc4-4b93-b643-6417ac75f31a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"4d0438c5-9dc4-4b93-b643-6417ac75f31a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"4d0438c5-9dc4-4b93-b643-6417ac75f31a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"4d0438c5-9dc4-4b93-b643-6417ac75f31a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"4d0438c5-9dc4-4b93-b643-6417ac75f31a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610539,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"5b1bde17-34b2-4c96-a240-52c83ddc5c93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610539} {\"correlation_id\":\"5b1bde17-34b2-4c96-a240-52c83ddc5c93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610539,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"5b1bde17-34b2-4c96-a240-52c83ddc5c93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610539,\"participants\":[{\"id\":996485,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996486,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"5b1bde17-34b2-4c96-a240-52c83ddc5c93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"5b1bde17-34b2-4c96-a240-52c83ddc5c93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"5b1bde17-34b2-4c96-a240-52c83ddc5c93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"5b1bde17-34b2-4c96-a240-52c83ddc5c93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"5b1bde17-34b2-4c96-a240-52c83ddc5c93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"5b1bde17-34b2-4c96-a240-52c83ddc5c93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"5b1bde17-34b2-4c96-a240-52c83ddc5c93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [ EsUpdateProcessManager ] Finished updating entities in ES {\"worker\":\"\",\"peak_memory\":\"99.73 MB\",\"elapsed_seconds\":1.19,\"update_target\":\"activities\",\"should_iterate_again\":false} {\"correlation_id\":\"4ad05333-9afb-492e-9f0f-b2909ac45b32\",\"trace_id\":\"3d8feb24-b173-4158-b0a4-4cf33af85066\"}\n[2026-05-11 10:17:53] local.WARNING: [Hubspot] No retry-after header or policy name found, using default {\"exception_class\":\"SevenShores\\\\Hubspot\\\\Exceptions\\\\BadRequest\"} {\"correlation_id\":\"5b1bde17-34b2-4c96-a240-52c83ddc5c93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.WARNING: [Hubspot] Received 429 from API {\"team_id\":2,\"config_id\":2,\"retry_after\":10,\"policy\":null,\"reason\":\"Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response:\n{\\\"status\\\":\\\"error\\\",\\\"message\\\":\\\"You have reached your secondly limit.\\\",\\\"errorType\\\":\\\"RATE_LIMIT\\\",\\\"correlationId\\\":\\\"019e168b-1 (truncated...)\n\"} {\"correlation_id\":\"5b1bde17-34b2-4c96-a240-52c83ddc5c93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"5b1bde17-34b2-4c96-a240-52c83ddc5c93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610915,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"88d5107a-d1a9-4def-8f1f-6ff8bea40516\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610915} {\"correlation_id\":\"88d5107a-d1a9-4def-8f1f-6ff8bea40516\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610915,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"88d5107a-d1a9-4def-8f1f-6ff8bea40516\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610915,\"participants\":[{\"id\":997104,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997105,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"88d5107a-d1a9-4def-8f1f-6ff8bea40516\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"88d5107a-d1a9-4def-8f1f-6ff8bea40516\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"88d5107a-d1a9-4def-8f1f-6ff8bea40516\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"88d5107a-d1a9-4def-8f1f-6ff8bea40516\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"88d5107a-d1a9-4def-8f1f-6ff8bea40516\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"88d5107a-d1a9-4def-8f1f-6ff8bea40516\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"88d5107a-d1a9-4def-8f1f-6ff8bea40516\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":12} {\"correlation_id\":\"88d5107a-d1a9-4def-8f1f-6ff8bea40516\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610878,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"9eb70001-f31f-427d-9ecb-d42969509f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610878} {\"correlation_id\":\"9eb70001-f31f-427d-9ecb-d42969509f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610878,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"9eb70001-f31f-427d-9ecb-d42969509f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610878,\"participants\":[{\"id\":997035,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997036,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"9eb70001-f31f-427d-9ecb-d42969509f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"9eb70001-f31f-427d-9ecb-d42969509f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"9eb70001-f31f-427d-9ecb-d42969509f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"9eb70001-f31f-427d-9ecb-d42969509f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"9eb70001-f31f-427d-9ecb-d42969509f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"9eb70001-f31f-427d-9ecb-d42969509f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"9eb70001-f31f-427d-9ecb-d42969509f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"9eb70001-f31f-427d-9ecb-d42969509f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610528,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"b291b19d-e631-4390-a8ce-49431d5f566f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610528} {\"correlation_id\":\"b291b19d-e631-4390-a8ce-49431d5f566f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610528,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"b291b19d-e631-4390-a8ce-49431d5f566f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610528,\"participants\":[{\"id\":996463,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996464,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"b291b19d-e631-4390-a8ce-49431d5f566f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b291b19d-e631-4390-a8ce-49431d5f566f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b291b19d-e631-4390-a8ce-49431d5f566f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"b291b19d-e631-4390-a8ce-49431d5f566f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"b291b19d-e631-4390-a8ce-49431d5f566f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"b291b19d-e631-4390-a8ce-49431d5f566f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"b291b19d-e631-4390-a8ce-49431d5f566f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"b291b19d-e631-4390-a8ce-49431d5f566f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610874,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"4b8fb89e-a1a0-4894-81d9-5d1e86570512\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610874} {\"correlation_id\":\"4b8fb89e-a1a0-4894-81d9-5d1e86570512\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610874,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"4b8fb89e-a1a0-4894-81d9-5d1e86570512\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610874,\"participants\":[{\"id\":997025,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997026,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"4b8fb89e-a1a0-4894-81d9-5d1e86570512\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4b8fb89e-a1a0-4894-81d9-5d1e86570512\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4b8fb89e-a1a0-4894-81d9-5d1e86570512\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"4b8fb89e-a1a0-4894-81d9-5d1e86570512\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"4b8fb89e-a1a0-4894-81d9-5d1e86570512\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"4b8fb89e-a1a0-4894-81d9-5d1e86570512\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"4b8fb89e-a1a0-4894-81d9-5d1e86570512\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"4b8fb89e-a1a0-4894-81d9-5d1e86570512\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610497,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"f27f33ba-8caa-49a5-9cad-cd8293e9a7db\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610497} {\"correlation_id\":\"f27f33ba-8caa-49a5-9cad-cd8293e9a7db\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610497,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"f27f33ba-8caa-49a5-9cad-cd8293e9a7db\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610497,\"participants\":[{\"id\":996401,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996402,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"f27f33ba-8caa-49a5-9cad-cd8293e9a7db\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"f27f33ba-8caa-49a5-9cad-cd8293e9a7db\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"f27f33ba-8caa-49a5-9cad-cd8293e9a7db\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"f27f33ba-8caa-49a5-9cad-cd8293e9a7db\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"f27f33ba-8caa-49a5-9cad-cd8293e9a7db\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"f27f33ba-8caa-49a5-9cad-cd8293e9a7db\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"f27f33ba-8caa-49a5-9cad-cd8293e9a7db\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":12} {\"correlation_id\":\"f27f33ba-8caa-49a5-9cad-cd8293e9a7db\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610617,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"af6121c1-ef51-49a6-acda-bb121812831a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610617} {\"correlation_id\":\"af6121c1-ef51-49a6-acda-bb121812831a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610617,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"af6121c1-ef51-49a6-acda-bb121812831a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610617,\"participants\":[{\"id\":996641,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996642,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"af6121c1-ef51-49a6-acda-bb121812831a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"af6121c1-ef51-49a6-acda-bb121812831a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"af6121c1-ef51-49a6-acda-bb121812831a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"af6121c1-ef51-49a6-acda-bb121812831a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"af6121c1-ef51-49a6-acda-bb121812831a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"af6121c1-ef51-49a6-acda-bb121812831a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"af6121c1-ef51-49a6-acda-bb121812831a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"af6121c1-ef51-49a6-acda-bb121812831a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610885,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"7c89eb2a-2a39-463f-abad-6b13e5fed935\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610885} {\"correlation_id\":\"7c89eb2a-2a39-463f-abad-6b13e5fed935\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610885,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"7c89eb2a-2a39-463f-abad-6b13e5fed935\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610885,\"participants\":[{\"id\":997051,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997052,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"7c89eb2a-2a39-463f-abad-6b13e5fed935\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"7c89eb2a-2a39-463f-abad-6b13e5fed935\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"7c89eb2a-2a39-463f-abad-6b13e5fed935\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"7c89eb2a-2a39-463f-abad-6b13e5fed935\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"7c89eb2a-2a39-463f-abad-6b13e5fed935\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"7c89eb2a-2a39-463f-abad-6b13e5fed935\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"7c89eb2a-2a39-463f-abad-6b13e5fed935\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":13} {\"correlation_id\":\"7c89eb2a-2a39-463f-abad-6b13e5fed935\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:56] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610867,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"9c37e4f5-1e21-4f96-86d0-2d8f2ce76d49\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:56] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610867} {\"correlation_id\":\"9c37e4f5-1e21-4f96-86d0-2d8f2ce76d49\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:56] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610867,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"9c37e4f5-1e21-4f96-86d0-2d8f2ce76d49\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:56] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610867,\"participants\":[{\"id\":997011,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997012,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"9c37e4f5-1e21-4f96-86d0-2d8f2ce76d49\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:56] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"9c37e4f5-1e21-4f96-86d0-2d8f2ce76d49\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:56] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"9c37e4f5-1e21-4f96-86d0-2d8f2ce76d49\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:56] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"9c37e4f5-1e21-4f96-86d0-2d8f2ce76d49\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:56] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"9c37e4f5-1e21-4f96-86d0-2d8f2ce76d49\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:56] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"9c37e4f5-1e21-4f96-86d0-2d8f2ce76d49\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:56] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"9c37e4f5-1e21-4f96-86d0-2d8f2ce76d49\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:56] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":12} {\"correlation_id\":\"9c37e4f5-1e21-4f96-86d0-2d8f2ce76d49\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:57] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610490,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"5a0ad4cc-8cdd-4f1e-8bae-a70a2f7b7280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:57] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610490} {\"correlation_id\":\"5a0ad4cc-8cdd-4f1e-8bae-a70a2f7b7280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:57] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610490,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"5a0ad4cc-8cdd-4f1e-8bae-a70a2f7b7280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:57] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610490,\"participants\":[{\"id\":996385,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996386,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"5a0ad4cc-8cdd-4f1e-8bae-a70a2f7b7280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:57] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"5a0ad4cc-8cdd-4f1e-8bae-a70a2f7b7280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:57] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"5a0ad4cc-8cdd-4f1e-8bae-a70a2f7b7280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:57] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"5a0ad4cc-8cdd-4f1e-8bae-a70a2f7b7280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:57] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"5a0ad4cc-8cdd-4f1e-8bae-a70a2f7b7280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:57] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"5a0ad4cc-8cdd-4f1e-8bae-a70a2f7b7280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:57] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"support@staging.jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/support%40staging.jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"correlation_id\":\"5a0ad4cc-8cdd-4f1e-8bae-a70a2f7b7280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:57] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"5a0ad4cc-8cdd-4f1e-8bae-a70a2f7b7280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:57] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"5a0ad4cc-8cdd-4f1e-8bae-a70a2f7b7280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:57] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610451,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"9884d6bc-6966-4c2b-b123-bd6bff97b920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:57] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610451} {\"correlation_id\":\"9884d6bc-6966-4c2b-b123-bd6bff97b920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:57] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610451,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"9884d6bc-6966-4c2b-b123-bd6bff97b920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610451,\"participants\":[{\"id\":996340,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996341,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"9884d6bc-6966-4c2b-b123-bd6bff97b920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"9884d6bc-6966-4c2b-b123-bd6bff97b920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"9884d6bc-6966-4c2b-b123-bd6bff97b920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"9884d6bc-6966-4c2b-b123-bd6bff97b920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"9884d6bc-6966-4c2b-b123-bd6bff97b920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"9884d6bc-6966-4c2b-b123-bd6bff97b920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"9884d6bc-6966-4c2b-b123-bd6bff97b920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"9884d6bc-6966-4c2b-b123-bd6bff97b920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614381,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"a7f9bc7e-977e-4032-820f-1e0b80c6214f\"}\n[2026-05-11 10:17:58] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614381} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"a7f9bc7e-977e-4032-820f-1e0b80c6214f\"}\n[2026-05-11 10:17:58] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614381,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"a7f9bc7e-977e-4032-820f-1e0b80c6214f\"}\n[2026-05-11 10:17:58] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614381,\"participants\":[{\"id\":1002630,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002631,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"a7f9bc7e-977e-4032-820f-1e0b80c6214f\"}\n[2026-05-11 10:17:58] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"a7f9bc7e-977e-4032-820f-1e0b80c6214f\"}\n[2026-05-11 10:17:58] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"a7f9bc7e-977e-4032-820f-1e0b80c6214f\"}\n[2026-05-11 10:17:58] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"a7f9bc7e-977e-4032-820f-1e0b80c6214f\"}\n[2026-05-11 10:17:58] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"a7f9bc7e-977e-4032-820f-1e0b80c6214f\"}\n[2026-05-11 10:17:58] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"a7f9bc7e-977e-4032-820f-1e0b80c6214f\"}\n[2026-05-11 10:17:58] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"a7f9bc7e-977e-4032-820f-1e0b80c6214f\"}\n[2026-05-11 10:17:58] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610764,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"4674593f-9f44-4f03-8474-ff0a7926a543\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610764} {\"correlation_id\":\"4674593f-9f44-4f03-8474-ff0a7926a543\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610764,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"4674593f-9f44-4f03-8474-ff0a7926a543\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610764,\"participants\":[{\"id\":996951,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996952,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"4674593f-9f44-4f03-8474-ff0a7926a543\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4674593f-9f44-4f03-8474-ff0a7926a543\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4674593f-9f44-4f03-8474-ff0a7926a543\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"4674593f-9f44-4f03-8474-ff0a7926a543\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"4674593f-9f44-4f03-8474-ff0a7926a543\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"4674593f-9f44-4f03-8474-ff0a7926a543\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"4674593f-9f44-4f03-8474-ff0a7926a543\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"4674593f-9f44-4f03-8474-ff0a7926a543\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610506,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"9c459c55-c8be-453e-9540-0477f5134f6f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610506} {\"correlation_id\":\"9c459c55-c8be-453e-9540-0477f5134f6f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610506,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"9c459c55-c8be-453e-9540-0477f5134f6f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610506,\"participants\":[{\"id\":996419,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996420,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"9c459c55-c8be-453e-9540-0477f5134f6f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"9c459c55-c8be-453e-9540-0477f5134f6f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"9c459c55-c8be-453e-9540-0477f5134f6f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"9c459c55-c8be-453e-9540-0477f5134f6f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"9c459c55-c8be-453e-9540-0477f5134f6f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"9c459c55-c8be-453e-9540-0477f5134f6f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"9c459c55-c8be-453e-9540-0477f5134f6f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":10} {\"correlation_id\":\"9c459c55-c8be-453e-9540-0477f5134f6f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610403,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"52ae8415-fd35-4109-8db4-45893cf37c4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610403} {\"correlation_id\":\"52ae8415-fd35-4109-8db4-45893cf37c4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610403,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"52ae8415-fd35-4109-8db4-45893cf37c4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610403,\"participants\":[{\"id\":996282,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996283,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"52ae8415-fd35-4109-8db4-45893cf37c4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"52ae8415-fd35-4109-8db4-45893cf37c4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"52ae8415-fd35-4109-8db4-45893cf37c4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"52ae8415-fd35-4109-8db4-45893cf37c4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"52ae8415-fd35-4109-8db4-45893cf37c4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"52ae8415-fd35-4109-8db4-45893cf37c4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"52ae8415-fd35-4109-8db4-45893cf37c4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":15} {\"correlation_id\":\"52ae8415-fd35-4109-8db4-45893cf37c4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614382,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3693e67e-875d-4232-a495-1621a90bf41a\"}\n[2026-05-11 10:17:58] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614382} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3693e67e-875d-4232-a495-1621a90bf41a\"}\n[2026-05-11 10:17:58] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614382,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3693e67e-875d-4232-a495-1621a90bf41a\"}\n[2026-05-11 10:17:58] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614382,\"participants\":[{\"id\":1002632,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002633,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3693e67e-875d-4232-a495-1621a90bf41a\"}\n[2026-05-11 10:17:58] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3693e67e-875d-4232-a495-1621a90bf41a\"}\n[2026-05-11 10:17:58] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3693e67e-875d-4232-a495-1621a90bf41a\"}\n[2026-05-11 10:17:58] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3693e67e-875d-4232-a495-1621a90bf41a\"}\n[2026-05-11 10:17:58] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3693e67e-875d-4232-a495-1621a90bf41a\"}\n[2026-05-11 10:17:58] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3693e67e-875d-4232-a495-1621a90bf41a\"}\n[2026-05-11 10:17:58] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3693e67e-875d-4232-a495-1621a90bf41a\"}\n[2026-05-11 10:17:58] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614436,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"56a279f5-3276-4781-9691-6ac712992a03\"}\n[2026-05-11 10:17:58] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614436} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"56a279f5-3276-4781-9691-6ac712992a03\"}\n[2026-05-11 10:17:58] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614436,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"56a279f5-3276-4781-9691-6ac712992a03\"}\n[2026-05-11 10:17:58] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614436,\"participants\":[{\"id\":1002751,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002752,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"56a279f5-3276-4781-9691-6ac712992a03\"}\n[2026-05-11 10:17:58] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"56a279f5-3276-4781-9691-6ac712992a03\"}\n[2026-05-11 10:17:58] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"56a279f5-3276-4781-9691-6ac712992a03\"}\n[2026-05-11 10:17:58] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"56a279f5-3276-4781-9691-6ac712992a03\"}\n[2026-05-11 10:17:58] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"56a279f5-3276-4781-9691-6ac712992a03\"}\n[2026-05-11 10:17:59] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"56a279f5-3276-4781-9691-6ac712992a03\"}\n[2026-05-11 10:17:59] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"56a279f5-3276-4781-9691-6ac712992a03\"}\n[2026-05-11 10:17:59] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612562,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"2149fff4-fc50-4b5e-8346-f4fe92446383\"}\n[2026-05-11 10:17:59] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612562} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"2149fff4-fc50-4b5e-8346-f4fe92446383\"}\n[2026-05-11 10:17:59] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612562,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"2149fff4-fc50-4b5e-8346-f4fe92446383\"}\n[2026-05-11 10:17:59] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612562,\"participants\":[{\"id\":999782,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999783,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"2149fff4-fc50-4b5e-8346-f4fe92446383\"}\n[2026-05-11 10:17:59] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"2149fff4-fc50-4b5e-8346-f4fe92446383\"}\n[2026-05-11 10:17:59] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"2149fff4-fc50-4b5e-8346-f4fe92446383\"}\n[2026-05-11 10:17:59] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"2149fff4-fc50-4b5e-8346-f4fe92446383\"}\n[2026-05-11 10:17:59] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"2149fff4-fc50-4b5e-8346-f4fe92446383\"}\n[2026-05-11 10:17:59] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"2149fff4-fc50-4b5e-8346-f4fe92446383\"}\n[2026-05-11 10:17:59] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"2149fff4-fc50-4b5e-8346-f4fe92446383\"}\n[2026-05-11 10:17:59] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610438,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"6c488719-2433-44c2-be14-6234030389cb\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:59] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610438} {\"correlation_id\":\"6c488719-2433-44c2-be14-6234030389cb\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:59] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610438,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"6c488719-2433-44c2-be14-6234030389cb\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:59] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610438,\"participants\":[{\"id\":996320,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996321,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"6c488719-2433-44c2-be14-6234030389cb\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:59] local.INFO: [ EsUpdateProcessManager ] Finished updating entities in ES {\"worker\":\"\",\"peak_memory\":\"99.73 MB\",\"elapsed_seconds\":0.31,\"update_target\":\"activities\",\"should_iterate_again\":false} {\"correlation_id\":\"4ad05333-9afb-492e-9f0f-b2909ac45b32\",\"trace_id\":\"3d8feb24-b173-4158-b0a4-4cf33af85066\"}\n[2026-05-11 10:17:59] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"6c488719-2433-44c2-be14-6234030389cb\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:59] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"6c488719-2433-44c2-be14-6234030389cb\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:59] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6c488719-2433-44c2-be14-6234030389cb\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:59] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"6c488719-2433-44c2-be14-6234030389cb\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:59] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"6c488719-2433-44c2-be14-6234030389cb\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:59] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"6c488719-2433-44c2-be14-6234030389cb\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:59] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":13} {\"correlation_id\":\"6c488719-2433-44c2-be14-6234030389cb\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:00] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612819,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"af37fbba-e927-4df9-840b-3ede48a1d911\"}\n[2026-05-11 10:18:00] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612819} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"af37fbba-e927-4df9-840b-3ede48a1d911\"}\n[2026-05-11 10:18:00] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612819,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"af37fbba-e927-4df9-840b-3ede48a1d911\"}\n[2026-05-11 10:18:00] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612819,\"participants\":[{\"id\":1000073,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1000074,\"user_id\":261,\"contact_id\":null,\"lead_id\":null},{\"id\":1000075,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"af37fbba-e927-4df9-840b-3ede48a1d911\"}\n[2026-05-11 10:18:00] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"af37fbba-e927-4df9-840b-3ede48a1d911\"}\n[2026-05-11 10:18:00] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"af37fbba-e927-4df9-840b-3ede48a1d911\"}\n[2026-05-11 10:18:00] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"af37fbba-e927-4df9-840b-3ede48a1d911\"}\n[2026-05-11 10:18:00] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"af37fbba-e927-4df9-840b-3ede48a1d911\"}\n[2026-05-11 10:18:00] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"af37fbba-e927-4df9-840b-3ede48a1d911\"}\n[2026-05-11 10:18:00] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612819,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"af37fbba-e927-4df9-840b-3ede48a1d911\"}\n[2026-05-11 10:18:00] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"af37fbba-e927-4df9-840b-3ede48a1d911\"}\n[2026-05-11 10:18:00] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"af37fbba-e927-4df9-840b-3ede48a1d911\"}\n[2026-05-11 10:18:00] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612847,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"534825cf-e6d0-42f8-8ff6-18fee9ebbcf9\"}\n[2026-05-11 10:18:00] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612847} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"534825cf-e6d0-42f8-8ff6-18fee9ebbcf9\"}\n[2026-05-11 10:18:00] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612847,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"534825cf-e6d0-42f8-8ff6-18fee9ebbcf9\"}\n[2026-05-11 10:18:00] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612847,\"participants\":[{\"id\":1000130,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1000131,\"user_id\":261,\"contact_id\":null,\"lead_id\":null},{\"id\":1000151,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"534825cf-e6d0-42f8-8ff6-18fee9ebbcf9\"}\n[2026-05-11 10:18:00] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"534825cf-e6d0-42f8-8ff6-18fee9ebbcf9\"}\n[2026-05-11 10:18:00] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"534825cf-e6d0-42f8-8ff6-18fee9ebbcf9\"}\n[2026-05-11 10:18:00] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"534825cf-e6d0-42f8-8ff6-18fee9ebbcf9\"}\n[2026-05-11 10:18:00] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"534825cf-e6d0-42f8-8ff6-18fee9ebbcf9\"}\n[2026-05-11 10:18:00] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"534825cf-e6d0-42f8-8ff6-18fee9ebbcf9\"}\n[2026-05-11 10:18:00] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"534825cf-e6d0-42f8-8ff6-18fee9ebbcf9\"}\n[2026-05-11 10:18:00] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610470,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"13c3f8a7-53c0-490e-915d-f30216c6fae9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:00] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610470} {\"correlation_id\":\"13c3f8a7-53c0-490e-915d-f30216c6fae9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:00] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610470,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"13c3f8a7-53c0-490e-915d-f30216c6fae9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:00] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610470,\"participants\":[{\"id\":996369,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996370,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"13c3f8a7-53c0-490e-915d-f30216c6fae9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:00] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"13c3f8a7-53c0-490e-915d-f30216c6fae9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:00] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"13c3f8a7-53c0-490e-915d-f30216c6fae9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:00] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"13c3f8a7-53c0-490e-915d-f30216c6fae9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:00] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"13c3f8a7-53c0-490e-915d-f30216c6fae9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:00] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"13c3f8a7-53c0-490e-915d-f30216c6fae9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:00] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"13c3f8a7-53c0-490e-915d-f30216c6fae9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:00] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":15} {\"correlation_id\":\"13c3f8a7-53c0-490e-915d-f30216c6fae9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610900,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"785d023d-231c-4c69-9e14-64b9f386cd8a\"}\n[2026-05-11 10:18:01] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610900} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"785d023d-231c-4c69-9e14-64b9f386cd8a\"}\n[2026-05-11 10:18:01] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610900,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"785d023d-231c-4c69-9e14-64b9f386cd8a\"}\n[2026-05-11 10:18:01] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610900,\"participants\":[{\"id\":997081,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997082,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"785d023d-231c-4c69-9e14-64b9f386cd8a\"}\n[2026-05-11 10:18:01] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"785d023d-231c-4c69-9e14-64b9f386cd8a\"}\n[2026-05-11 10:18:01] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"785d023d-231c-4c69-9e14-64b9f386cd8a\"}\n[2026-05-11 10:18:01] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"785d023d-231c-4c69-9e14-64b9f386cd8a\"}\n[2026-05-11 10:18:01] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"785d023d-231c-4c69-9e14-64b9f386cd8a\"}\n[2026-05-11 10:18:01] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"785d023d-231c-4c69-9e14-64b9f386cd8a\"}\n[2026-05-11 10:18:01] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"785d023d-231c-4c69-9e14-64b9f386cd8a\"}\n[2026-05-11 10:18:01] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610426,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"aea37783-669f-433b-aac7-ead252f60285\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610426} {\"correlation_id\":\"aea37783-669f-433b-aac7-ead252f60285\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610426,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"aea37783-669f-433b-aac7-ead252f60285\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610426,\"participants\":[{\"id\":996306,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996307,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"aea37783-669f-433b-aac7-ead252f60285\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"aea37783-669f-433b-aac7-ead252f60285\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"aea37783-669f-433b-aac7-ead252f60285\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"aea37783-669f-433b-aac7-ead252f60285\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"aea37783-669f-433b-aac7-ead252f60285\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"aea37783-669f-433b-aac7-ead252f60285\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"aea37783-669f-433b-aac7-ead252f60285\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":10} {\"correlation_id\":\"aea37783-669f-433b-aac7-ead252f60285\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610935,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73386989-234b-4074-93cd-b907d73fb039\"}\n[2026-05-11 10:18:01] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610935} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73386989-234b-4074-93cd-b907d73fb039\"}\n[2026-05-11 10:18:01] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610935,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73386989-234b-4074-93cd-b907d73fb039\"}\n[2026-05-11 10:18:01] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610935,\"participants\":[{\"id\":997141,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997142,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73386989-234b-4074-93cd-b907d73fb039\"}\n[2026-05-11 10:18:01] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73386989-234b-4074-93cd-b907d73fb039\"}\n[2026-05-11 10:18:01] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73386989-234b-4074-93cd-b907d73fb039\"}\n[2026-05-11 10:18:01] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73386989-234b-4074-93cd-b907d73fb039\"}\n[2026-05-11 10:18:01] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73386989-234b-4074-93cd-b907d73fb039\"}\n[2026-05-11 10:18:01] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73386989-234b-4074-93cd-b907d73fb039\"}\n[2026-05-11 10:18:01] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73386989-234b-4074-93cd-b907d73fb039\"}\n[2026-05-11 10:18:01] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612560,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"67837137-7da9-4fc3-807c-fa87dbcc5090\"}\n[2026-05-11 10:18:01] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612560} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"67837137-7da9-4fc3-807c-fa87dbcc5090\"}\n[2026-05-11 10:18:01] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612560,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"67837137-7da9-4fc3-807c-fa87dbcc5090\"}\n[2026-05-11 10:18:01] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612560,\"participants\":[{\"id\":999778,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999779,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"67837137-7da9-4fc3-807c-fa87dbcc5090\"}\n[2026-05-11 10:18:01] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"67837137-7da9-4fc3-807c-fa87dbcc5090\"}\n[2026-05-11 10:18:01] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"67837137-7da9-4fc3-807c-fa87dbcc5090\"}\n[2026-05-11 10:18:01] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"67837137-7da9-4fc3-807c-fa87dbcc5090\"}\n[2026-05-11 10:18:01] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"67837137-7da9-4fc3-807c-fa87dbcc5090\"}\n[2026-05-11 10:18:01] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"67837137-7da9-4fc3-807c-fa87dbcc5090\"}\n[2026-05-11 10:18:01] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"67837137-7da9-4fc3-807c-fa87dbcc5090\"}\n[2026-05-11 10:18:01] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612561,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1d0c22f1-5e71-452c-94ab-4a7ba39ee8be\"}\n[2026-05-11 10:18:01] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612561} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1d0c22f1-5e71-452c-94ab-4a7ba39ee8be\"}\n[2026-05-11 10:18:01] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612561,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1d0c22f1-5e71-452c-94ab-4a7ba39ee8be\"}\n[2026-05-11 10:18:01] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612561,\"participants\":[{\"id\":999780,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999781,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1d0c22f1-5e71-452c-94ab-4a7ba39ee8be\"}\n[2026-05-11 10:18:01] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1d0c22f1-5e71-452c-94ab-4a7ba39ee8be\"}\n[2026-05-11 10:18:01] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1d0c22f1-5e71-452c-94ab-4a7ba39ee8be\"}\n[2026-05-11 10:18:01] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1d0c22f1-5e71-452c-94ab-4a7ba39ee8be\"}\n[2026-05-11 10:18:01] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1d0c22f1-5e71-452c-94ab-4a7ba39ee8be\"}\n[2026-05-11 10:18:01] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612561,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1d0c22f1-5e71-452c-94ab-4a7ba39ee8be\"}\n[2026-05-11 10:18:01] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"447700174614.447782589921.OeREojLVnk@txt.staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1d0c22f1-5e71-452c-94ab-4a7ba39ee8be\"}\n[2026-05-11 10:18:01] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"447700174614.447782589921.OeREojLVnk@txt.staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1d0c22f1-5e71-452c-94ab-4a7ba39ee8be\"}\n[2026-05-11 10:18:01] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610462,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"5e4163ac-fdc7-49df-89de-383bf3f5bcd4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610462} {\"correlation_id\":\"5e4163ac-fdc7-49df-89de-383bf3f5bcd4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610462,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"5e4163ac-fdc7-49df-89de-383bf3f5bcd4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610462,\"participants\":[{\"id\":996353,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996354,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"5e4163ac-fdc7-49df-89de-383bf3f5bcd4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"5e4163ac-fdc7-49df-89de-383bf3f5bcd4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"5e4163ac-fdc7-49df-89de-383bf3f5bcd4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"5e4163ac-fdc7-49df-89de-383bf3f5bcd4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"5e4163ac-fdc7-49df-89de-383bf3f5bcd4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"5e4163ac-fdc7-49df-89de-383bf3f5bcd4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"5e4163ac-fdc7-49df-89de-383bf3f5bcd4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":10} {\"correlation_id\":\"5e4163ac-fdc7-49df-89de-383bf3f5bcd4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:02] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614378,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":6167,\"account_id\":null,\"opportunity_id\":null,\"stage_id\":null}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9476099f-6f93-4402-b763-b075c4f8ed44\"}\n[2026-05-11 10:18:02] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614378} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9476099f-6f93-4402-b763-b075c4f8ed44\"}\n[2026-05-11 10:18:02] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614378,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9476099f-6f93-4402-b763-b075c4f8ed44\"}\n[2026-05-11 10:18:02] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614378,\"participants\":[{\"id\":1002623,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002624,\"user_id\":null,\"contact_id\":6167,\"lead_id\":null},{\"id\":1002625,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9476099f-6f93-4402-b763-b075c4f8ed44\"}\n[2026-05-11 10:18:02] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9476099f-6f93-4402-b763-b075c4f8ed44\"}\n[2026-05-11 10:18:02] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9476099f-6f93-4402-b763-b075c4f8ed44\"}\n[2026-05-11 10:18:02] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9476099f-6f93-4402-b763-b075c4f8ed44\"}\n[2026-05-11 10:18:02] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9476099f-6f93-4402-b763-b075c4f8ed44\"}\n[2026-05-11 10:18:02] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9476099f-6f93-4402-b763-b075c4f8ed44\"}\n[2026-05-11 10:18:02] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9476099f-6f93-4402-b763-b075c4f8ed44\"}\n[2026-05-11 10:18:03] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":615092,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7e0e12d1-b270-490b-848b-763e373c90e0\"}\n[2026-05-11 10:18:03] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":615092} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7e0e12d1-b270-490b-848b-763e373c90e0\"}\n[2026-05-11 10:18:03] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":615092,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7e0e12d1-b270-490b-848b-763e373c90e0\"}\n[2026-05-11 10:18:03] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":615092,\"participants\":[{\"id\":1004102,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1004103,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7e0e12d1-b270-490b-848b-763e373c90e0\"}\n[2026-05-11 10:18:03] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7e0e12d1-b270-490b-848b-763e373c90e0\"}\n[2026-05-11 10:18:03] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7e0e12d1-b270-490b-848b-763e373c90e0\"}\n[2026-05-11 10:18:03] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7e0e12d1-b270-490b-848b-763e373c90e0\"}\n[2026-05-11 10:18:03] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7e0e12d1-b270-490b-848b-763e373c90e0\"}\n[2026-05-11 10:18:03] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7e0e12d1-b270-490b-848b-763e373c90e0\"}\n[2026-05-11 10:18:03] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7e0e12d1-b270-490b-848b-763e373c90e0\"}\n[2026-05-11 10:18:03] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611451,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"adaf1f1e-8477-469f-86c9-9c59d2623f11\"}\n[2026-05-11 10:18:03] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611451} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"adaf1f1e-8477-469f-86c9-9c59d2623f11\"}\n[2026-05-11 10:18:03] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611451,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"adaf1f1e-8477-469f-86c9-9c59d2623f11\"}\n[2026-05-11 10:18:03] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611451,\"participants\":[{\"id\":997955,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997956,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"adaf1f1e-8477-469f-86c9-9c59d2623f11\"}\n[2026-05-11 10:18:03] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"adaf1f1e-8477-469f-86c9-9c59d2623f11\"}\n[2026-05-11 10:18:03] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"adaf1f1e-8477-469f-86c9-9c59d2623f11\"}\n[2026-05-11 10:18:03] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"adaf1f1e-8477-469f-86c9-9c59d2623f11\"}\n[2026-05-11 10:18:03] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"adaf1f1e-8477-469f-86c9-9c59d2623f11\"}\n[2026-05-11 10:18:03] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"adaf1f1e-8477-469f-86c9-9c59d2623f11\"}\n[2026-05-11 10:18:03] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"adaf1f1e-8477-469f-86c9-9c59d2623f11\"}\n[2026-05-11 10:18:03] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612336,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1235043b-578e-49e0-9ebe-230be6d9a8f8\"}\n[2026-05-11 10:18:03] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612336} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1235043b-578e-49e0-9ebe-230be6d9a8f8\"}\n[2026-05-11 10:18:03] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612336,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1235043b-578e-49e0-9ebe-230be6d9a8f8\"}\n[2026-05-11 10:18:03] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612336,\"participants\":[{\"id\":999508,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999509,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999512,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999513,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1235043b-578e-49e0-9ebe-230be6d9a8f8\"}\n[2026-05-11 10:18:03] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1235043b-578e-49e0-9ebe-230be6d9a8f8\"}\n[2026-05-11 10:18:03] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1235043b-578e-49e0-9ebe-230be6d9a8f8\"}\n[2026-05-11 10:18:03] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1235043b-578e-49e0-9ebe-230be6d9a8f8\"}\n[2026-05-11 10:18:03] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1235043b-578e-49e0-9ebe-230be6d9a8f8\"}\n[2026-05-11 10:18:03] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1235043b-578e-49e0-9ebe-230be6d9a8f8\"}\n[2026-05-11 10:18:03] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612336,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1235043b-578e-49e0-9ebe-230be6d9a8f8\"}\n[2026-05-11 10:18:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610539,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610539} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610539,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:04] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610539,\"participants\":[{\"id\":996485,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996486,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:04] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:04] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:04] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:04] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:04] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:04] local.INFO: [ EsUpdateProcessManager ] Finished updating entities in ES {\"worker\":\"\",\"peak_memory\":\"99.73 MB\",\"elapsed_seconds\":0.47,\"update_target\":\"activities\",\"should_iterate_again\":false} {\"correlation_id\":\"4ad05333-9afb-492e-9f0f-b2909ac45b32\",\"trace_id\":\"3d8feb24-b173-4158-b0a4-4cf33af85066\"}\n[2026-05-11 10:18:04] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/contact/search\",\"total_requests\":1,\"total_records_fetched\":0,\"total_elapsed_seconds\":0.3,\"average_seconds_per_request\":0.3} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:05] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:05] local.INFO: [Prospect match] Cache miss {\"identifier_type\":\"domain\",\"identifier\":\"jiminny.com\",\"crm\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:05] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"domain\",\"identifier\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:05] local.INFO: [HubSpot] importAccount {\"crm_provider_id\":\"749766179\",\"config_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:05] local.INFO: [HubSpot] CRM Search requested {\"request\":{\"filterGroups\":[{\"filters\":[{\"propertyName\":\"associations.company\",\"operator\":\"EQ\",\"value\":\"749766179\"},{\"propertyName\":\"dealstage\",\"operator\":\"NOT_IN\",\"values\":[\"closedwon\",\"4040964\",\"59247967\"]},{\"propertyName\":\"dealstage\",\"operator\":\"NOT_IN\",\"values\":[\"closedlost\",\"4040965\",\"59247968\"]}]}],\"sorts\":[{\"propertyName\":\"modifieddate\",\"direction\":\"DESCENDING\"}],\"properties\":[\"dealname\",\"amount\",\"hubspot_owner_id\",\"pipeline\",\"dealstage\",\"closedate\",\"deal_currency_code\"],\"limit\":200}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:05] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/deals/search\",\"total_requests\":1,\"total_records_fetched\":10,\"total_elapsed_seconds\":0.24,\"average_seconds_per_request\":0.24} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"1042ef38-481f-4e55-9261-bb89ceb4cd6f\",\"trace_id\":\"3cbbfc20-36d7-4827-9e77-e5ea12d34c82\"}\n[2026-05-11 10:18:06] local.INFO: [ScheduleBotCommand] Number of activities to be captured: 0 {\"correlation_id\":\"1042ef38-481f-4e55-9261-bb89ceb4cd6f\",\"trace_id\":\"3cbbfc20-36d7-4827-9e77-e5ea12d34c82\"}\n[2026-05-11 10:18:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"1042ef38-481f-4e55-9261-bb89ceb4cd6f\",\"trace_id\":\"3cbbfc20-36d7-4827-9e77-e5ea12d34c82\"}\n[2026-05-11 10:18:06] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610539,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:06] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610539,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610539} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610539,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:06] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610539,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:06] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610878,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610878} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610878,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:06] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610878,\"participants\":[{\"id\":997035,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997036,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:06] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:06] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:06] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:06] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:06] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:06] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:06] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:06] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610878,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:07] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610878,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610878} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610878,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:07] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610878,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:07] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612340,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612340} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612340,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:07] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612340,\"participants\":[{\"id\":999516,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999517,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999518,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999519,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:07] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:07] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:07] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:07] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:07] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:07] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612340,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:07] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/contact/search\",\"total_requests\":1,\"total_records_fetched\":0,\"total_elapsed_seconds\":0.25,\"average_seconds_per_request\":0.25} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:07] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/contact/search\",\"total_requests\":1,\"total_records_fetched\":0,\"total_elapsed_seconds\":0.48,\"average_seconds_per_request\":0.48} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:07] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612340,\"participants_processed\":4,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612340} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612340,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:07] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612340,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:08] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612360,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bea3a6fc-5389-4a59-a601-2f8fe9a2d01c\"}\n[2026-05-11 10:18:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612360} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bea3a6fc-5389-4a59-a601-2f8fe9a2d01c\"}\n[2026-05-11 10:18:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612360,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bea3a6fc-5389-4a59-a601-2f8fe9a2d01c\"}\n[2026-05-11 10:18:08] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612360,\"participants\":[{\"id\":999552,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999553,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999565,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bea3a6fc-5389-4a59-a601-2f8fe9a2d01c\"}\n[2026-05-11 10:18:08] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bea3a6fc-5389-4a59-a601-2f8fe9a2d01c\"}\n[2026-05-11 10:18:08] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bea3a6fc-5389-4a59-a601-2f8fe9a2d01c\"}\n[2026-05-11 10:18:08] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bea3a6fc-5389-4a59-a601-2f8fe9a2d01c\"}\n[2026-05-11 10:18:08] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bea3a6fc-5389-4a59-a601-2f8fe9a2d01c\"}\n[2026-05-11 10:18:08] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bea3a6fc-5389-4a59-a601-2f8fe9a2d01c\"}\n[2026-05-11 10:18:08] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612360,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bea3a6fc-5389-4a59-a601-2f8fe9a2d01c\"}\n[2026-05-11 10:18:08] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612360,\"participants_processed\":3,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bea3a6fc-5389-4a59-a601-2f8fe9a2d01c\"}\n[2026-05-11 10:18:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612360} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bea3a6fc-5389-4a59-a601-2f8fe9a2d01c\"}\n[2026-05-11 10:18:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612360,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bea3a6fc-5389-4a59-a601-2f8fe9a2d01c\"}\n[2026-05-11 10:18:08] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612360,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bea3a6fc-5389-4a59-a601-2f8fe9a2d01c\"}\n[2026-05-11 10:18:08] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612339,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f92f5ee2-fe1d-48c0-812c-1ef5822e650b\"}\n[2026-05-11 10:18:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612339} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f92f5ee2-fe1d-48c0-812c-1ef5822e650b\"}\n[2026-05-11 10:18:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612339,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f92f5ee2-fe1d-48c0-812c-1ef5822e650b\"}\n[2026-05-11 10:18:08] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612339,\"participants\":[{\"id\":999514,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999515,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999540,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f92f5ee2-fe1d-48c0-812c-1ef5822e650b\"}\n[2026-05-11 10:18:08] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f92f5ee2-fe1d-48c0-812c-1ef5822e650b\"}\n[2026-05-11 10:18:08] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f92f5ee2-fe1d-48c0-812c-1ef5822e650b\"}\n[2026-05-11 10:18:08] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f92f5ee2-fe1d-48c0-812c-1ef5822e650b\"}\n[2026-05-11 10:18:08] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f92f5ee2-fe1d-48c0-812c-1ef5822e650b\"}\n[2026-05-11 10:18:08] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f92f5ee2-fe1d-48c0-812c-1ef5822e650b\"}\n[2026-05-11 10:18:08] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612339,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f92f5ee2-fe1d-48c0-812c-1ef5822e650b\"}\n[2026-05-11 10:18:08] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612339,\"participants_processed\":3,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f92f5ee2-fe1d-48c0-812c-1ef5822e650b\"}\n[2026-05-11 10:18:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612339} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f92f5ee2-fe1d-48c0-812c-1ef5822e650b\"}\n[2026-05-11 10:18:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612339,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f92f5ee2-fe1d-48c0-812c-1ef5822e650b\"}\n[2026-05-11 10:18:08] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612339,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f92f5ee2-fe1d-48c0-812c-1ef5822e650b\"}\n[2026-05-11 10:18:08] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611455,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611455} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611455,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:08] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611455,\"participants\":[{\"id\":997961,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997962,\"user_id\":1460,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:08] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:08] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:08] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:08] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:08] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:08] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"support@staging.jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/support%40staging.jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:08] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:09] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/contact/search\",\"total_requests\":1,\"total_records_fetched\":0,\"total_elapsed_seconds\":0.66,\"average_seconds_per_request\":0.66} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:09] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:09] local.INFO: [Prospect match] Cache miss {\"identifier_type\":\"domain\",\"identifier\":\"jiminny.com\",\"crm\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:09] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"domain\",\"identifier\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:09] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"e0173b67-adc7-4861-acea-33ec563fa8bc\",\"trace_id\":\"df5cbecf-dde1-4674-82c8-8b7a2f4b74de\"}\n[2026-05-11 10:18:09] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"e0173b67-adc7-4861-acea-33ec563fa8bc\",\"trace_id\":\"df5cbecf-dde1-4674-82c8-8b7a2f4b74de\"}\n[2026-05-11 10:18:09] local.INFO: [HubSpot] importAccount {\"crm_provider_id\":\"749766179\",\"config_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:09] local.INFO: [HubSpot] CRM Search requested {\"request\":{\"filterGroups\":[{\"filters\":[{\"propertyName\":\"associations.company\",\"operator\":\"EQ\",\"value\":\"749766179\"},{\"propertyName\":\"dealstage\",\"operator\":\"NOT_IN\",\"values\":[\"closedwon\",\"4040964\",\"59247967\"]},{\"propertyName\":\"dealstage\",\"operator\":\"NOT_IN\",\"values\":[\"closedlost\",\"4040965\",\"59247968\"]}]}],\"sorts\":[{\"propertyName\":\"modifieddate\",\"direction\":\"DESCENDING\"}],\"properties\":[\"dealname\",\"amount\",\"hubspot_owner_id\",\"pipeline\",\"dealstage\",\"closedate\",\"deal_currency_code\"],\"limit\":200}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:09] local.INFO: [ EsUpdateProcessManager ] Finished updating entities in ES {\"worker\":\"\",\"peak_memory\":\"99.73 MB\",\"elapsed_seconds\":0.3,\"update_target\":\"activities\",\"should_iterate_again\":false} {\"correlation_id\":\"4ad05333-9afb-492e-9f0f-b2909ac45b32\",\"trace_id\":\"3d8feb24-b173-4158-b0a4-4cf33af85066\"}\n[2026-05-11 10:18:09] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/deals/search\",\"total_requests\":1,\"total_records_fetched\":10,\"total_elapsed_seconds\":0.26,\"average_seconds_per_request\":0.26} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":611455,\"team_id\":2,\"email\":\"aneliya.angelova@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":611455,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611455} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611455,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":611455,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610915,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610915} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610915,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610915,\"participants\":[{\"id\":997104,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997105,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610915,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610915,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610915} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610915,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610915,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610528,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610528} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610528,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610528,\"participants\":[{\"id\":996463,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996464,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610528,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610528,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610528} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610528,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610528,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611087,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611087} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611087,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611087,\"participants\":[{\"id\":997368,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997369,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":611087,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":611087,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611087} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611087,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":611087,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611076,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611076} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611076,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611076,\"participants\":[{\"id\":997346,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997347,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":611076,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":611076,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611076} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611076,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":611076,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610497,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610497} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610497,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610497,\"participants\":[{\"id\":996401,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996402,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610497,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610497,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610497} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610497,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610497,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610867,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610867} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610867,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610867,\"participants\":[{\"id\":997011,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997012,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610867,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610867,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610867} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610867,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610867,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610490,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610490} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610490,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610490,\"participants\":[{\"id\":996385,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996386,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610490,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610490,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610490} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610490,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610490,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610506,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610506} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610506,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610506,\"participants\":[{\"id\":996419,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996420,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610506,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610506,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610506} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610506,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610506,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610885,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610885} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610885,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:11] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610885,\"participants\":[{\"id\":997051,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997052,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:11] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:11] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:11] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:11] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:11] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:11] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:11] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:11] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610885,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:11] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610885,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:11] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610885} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:11] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610885,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:11] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610885,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:11] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610874,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610874} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610874,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610874,\"participants\":[{\"id\":997025,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997026,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610874,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610874,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610874} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610874,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610874,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610617,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610617} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610617,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610617,\"participants\":[{\"id\":996641,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996642,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610617,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610617,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610617} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610617,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610617,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614382,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:11] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614382} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:11] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614382,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:11] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614382,\"participants\":[{\"id\":1002632,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002633,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:11] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:11] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:11] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:11] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:11] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:11] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"nikolay.nikolov@jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/nikolay.nikolov%40jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:11] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:11] local.NOTICE: Monitoring start {\"correlation_id\":\"f1c8fc03-337f-4edb-a859-cd9fb18b900e\",\"trace_id\":\"503eff58-a255-4b63-9001-481d9a9bd530\"}\n[2026-05-11 10:18:11] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/contact/search\",\"total_requests\":1,\"total_records_fetched\":0,\"total_elapsed_seconds\":0.27,\"average_seconds_per_request\":0.27} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:11] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"nikolay.nikolov@jiminny.com\",\"domain\":\"jiminny.com\"} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:11] local.INFO: [Prospect match] Cache miss {\"identifier_type\":\"domain\",\"identifier\":\"jiminny.com\",\"crm\":\"hubspot\"} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:11] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"domain\",\"identifier\":\"jiminny.com\"} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:11] local.NOTICE: Monitoring end {\"correlation_id\":\"f1c8fc03-337f-4edb-a859-cd9fb18b900e\",\"trace_id\":\"503eff58-a255-4b63-9001-481d9a9bd530\"}\n[2026-05-11 10:18:12] local.INFO: [HubSpot] importAccount {\"crm_provider_id\":\"749766179\",\"config_id\":2} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:12] local.INFO: [HubSpot] CRM Search requested {\"request\":{\"filterGroups\":[{\"filters\":[{\"propertyName\":\"associations.company\",\"operator\":\"EQ\",\"value\":\"749766179\"},{\"propertyName\":\"dealstage\",\"operator\":\"NOT_IN\",\"values\":[\"closedwon\",\"4040964\",\"59247967\"]},{\"propertyName\":\"dealstage\",\"operator\":\"NOT_IN\",\"values\":[\"closedlost\",\"4040965\",\"59247968\"]}]}],\"sorts\":[{\"propertyName\":\"modifieddate\",\"direction\":\"DESCENDING\"}],\"properties\":[\"dealname\",\"amount\",\"hubspot_owner_id\",\"pipeline\",\"dealstage\",\"closedate\",\"deal_currency_code\"],\"limit\":200}} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:12] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/deals/search\",\"total_requests\":1,\"total_records_fetched\":10,\"total_elapsed_seconds\":0.42,\"average_seconds_per_request\":0.42} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:14] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":614382,\"team_id\":2,\"email\":\"nikolay.nikolov@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:14] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":614382,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:14] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614382} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:14] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614382,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":614382,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614381,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614381} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614381,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614381,\"participants\":[{\"id\":1002630,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002631,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"nikolay.nikolov@jiminny.com\",\"domain\":\"jiminny.com\"} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":614381,\"team_id\":2,\"email\":\"nikolay.nikolov@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":614381,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614381} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614381,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":614381,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [ EsUpdateProcessManager ] Finished updating entities in ES {\"worker\":\"\",\"peak_memory\":\"99.73 MB\",\"elapsed_seconds\":0.55,\"update_target\":\"activities\",\"should_iterate_again\":false} {\"correlation_id\":\"4ad05333-9afb-492e-9f0f-b2909ac45b32\",\"trace_id\":\"3d8feb24-b173-4158-b0a4-4cf33af85066\"}\n[2026-05-11 10:18:15] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610426,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:15] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610426} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:15] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610426,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:15] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610426,\"participants\":[{\"id\":996306,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996307,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:15] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:15] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:15] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:15] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:15] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:15] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:15] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:15] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610426,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:15] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610426,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:15] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610426} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:15] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610426,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:15] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610426,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:16] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612560,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:16] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612560} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:16] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612560,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:16] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612560,\"participants\":[{\"id\":999778,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999779,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:16] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:16] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:16] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:16] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:16] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:16] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"447782589921@txt.staging.jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/447782589921%40txt.staging.jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:16] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:16] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/contact/search\",\"total_requests\":1,\"total_records_fetched\":0,\"total_elapsed_seconds\":0.27,\"average_seconds_per_request\":0.27} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:16] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"447782589921@txt.staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:16] local.INFO: [Prospect match] Cache miss {\"identifier_type\":\"domain\",\"identifier\":\"jiminny.com\",\"crm\":\"hubspot\"} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:16] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"domain\",\"identifier\":\"jiminny.com\"} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:17] local.INFO: [HubSpot] importAccount {\"crm_provider_id\":\"749766179\",\"config_id\":2} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:17] local.INFO: [HubSpot] CRM Search requested {\"request\":{\"filterGroups\":[{\"filters\":[{\"propertyName\":\"associations.company\",\"operator\":\"EQ\",\"value\":\"749766179\"},{\"propertyName\":\"dealstage\",\"operator\":\"NOT_IN\",\"values\":[\"closedwon\",\"4040964\",\"59247967\"]},{\"propertyName\":\"dealstage\",\"operator\":\"NOT_IN\",\"values\":[\"closedlost\",\"4040965\",\"59247968\"]}]}],\"sorts\":[{\"propertyName\":\"modifieddate\",\"direction\":\"DESCENDING\"}],\"properties\":[\"dealname\",\"amount\",\"hubspot_owner_id\",\"pipeline\",\"dealstage\",\"closedate\",\"deal_currency_code\"],\"limit\":200}} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:17] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/deals/search\",\"total_requests\":1,\"total_records_fetched\":10,\"total_elapsed_seconds\":0.23,\"average_seconds_per_request\":0.23} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"4f01fa5e-5837-4b03-af04-ccad937f80f4\",\"trace_id\":\"7ea236cf-a366-4cea-8e77-3417ec22eac5\"}\n[2026-05-11 10:18:18] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"4f01fa5e-5837-4b03-af04-ccad937f80f4\",\"trace_id\":\"7ea236cf-a366-4cea-8e77-3417ec22eac5\"}\n[2026-05-11 10:18:18] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612560,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612560,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612560} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612560,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612560,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610462,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610462} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610462,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610462,\"participants\":[{\"id\":996353,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996354,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610462,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610462,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610462} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610462,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610462,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612819,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612819} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612819,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612819,\"participants\":[{\"id\":1000073,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1000074,\"user_id\":261,\"contact_id\":null,\"lead_id\":null},{\"id\":1000075,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: ProspectCache - Searching DB for opportunity by owner {\"account_id\":244,\"contact_id\":4487,\"owner_id\":261} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: ProspectCache - Opportunity DB search results {\"account_id\":244,\"contact_id\":4487,\"opportunity_id\":299} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612819,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"adelina.petrova@jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/adelina.petrova%40jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/contact/search\",\"total_requests\":1,\"total_records_fetched\":0,\"total_elapsed_seconds\":0.24,\"average_seconds_per_request\":0.24} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"adelina.petrova@jiminny.com\",\"domain\":\"jiminny.com\"} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [Prospect match] Cache miss {\"identifier_type\":\"domain\",\"identifier\":\"jiminny.com\",\"crm\":\"hubspot\"} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"domain\",\"identifier\":\"jiminny.com\"} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:19] local.INFO: [HubSpot] importAccount {\"crm_provider_id\":\"749766179\",\"config_id\":2} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:19] local.INFO: [HubSpot] CRM Search requested {\"request\":{\"filterGroups\":[{\"filters\":[{\"propertyName\":\"associations.company\",\"operator\":\"EQ\",\"value\":\"749766179\"},{\"propertyName\":\"dealstage\",\"operator\":\"NOT_IN\",\"values\":[\"closedwon\",\"4040964\",\"59247967\"]},{\"propertyName\":\"dealstage\",\"operator\":\"NOT_IN\",\"values\":[\"closedlost\",\"4040965\",\"59247968\"]}]}],\"sorts\":[{\"propertyName\":\"modifieddate\",\"direction\":\"DESCENDING\"}],\"properties\":[\"dealname\",\"amount\",\"hubspot_owner_id\",\"pipeline\",\"dealstage\",\"closedate\",\"deal_currency_code\"],\"limit\":200}} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:19] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/deals/search\",\"total_requests\":1,\"total_records_fetched\":10,\"total_elapsed_seconds\":0.23,\"average_seconds_per_request\":0.23} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:19] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"add7477b-8e9d-44ef-9c16-cf763d7fd973\",\"trace_id\":\"0a4036d4-4c6b-4724-8efb-d8375a7dfe6a\"}\n[2026-05-11 10:18:19] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"add7477b-8e9d-44ef-9c16-cf763d7fd973\",\"trace_id\":\"0a4036d4-4c6b-4724-8efb-d8375a7dfe6a\"}\n[2026-05-11 10:18:19] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"add7477b-8e9d-44ef-9c16-cf763d7fd973\",\"trace_id\":\"0a4036d4-4c6b-4724-8efb-d8375a7dfe6a\"}\n[2026-05-11 10:18:19] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"add7477b-8e9d-44ef-9c16-cf763d7fd973\",\"trace_id\":\"0a4036d4-4c6b-4724-8efb-d8375a7dfe6a\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612819,\"participants_processed\":3,\"exact_matches\":1,\"domain_matches\":1,\"best_match_found\":true} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612819} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612819,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612819,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612847,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612847} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612847,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612847,\"participants\":[{\"id\":1000130,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1000131,\"user_id\":261,\"contact_id\":null,\"lead_id\":null},{\"id\":1000151,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null}]} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"adelina.petrova@jiminny.com\",\"domain\":\"jiminny.com\"} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612847,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612847,\"participants_processed\":3,\"exact_matches\":1,\"domain_matches\":1,\"best_match_found\":true} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612847} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612847,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612847,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610451,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610451} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610451,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610451,\"participants\":[{\"id\":996340,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996341,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610451,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610451,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610451} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610451,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610451,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612562,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612562} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612562,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612562,\"participants\":[{\"id\":999782,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999783,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"447782589921@txt.staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612562,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612562,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612562} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612562,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612562,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610764,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610764} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610764,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610764,\"participants\":[{\"id\":996951,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996952,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610764,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610764,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610764} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610764,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610764,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614436,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614436} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614436,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614436,\"participants\":[{\"id\":1002751,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002752,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"nikolay.nikolov@jiminny.com\",\"domain\":\"jiminny.com\"} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":614436,\"team_id\":2,\"email\":\"nikolay.nikolov@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":614436,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614436} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614436,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":614436,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610438,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610438} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610438,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610438,\"participants\":[{\"id\":996320,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996321,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610438,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610438,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610438} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610438,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610438,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":615092,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":615092} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":615092,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":615092,\"participants\":[{\"id\":1004102,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1004103,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"nikolay.nikolov@jiminny.com\",\"domain\":\"jiminny.com\"} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":615092,\"team_id\":2,\"email\":\"nikolay.nikolov@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":615092,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":615092} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":615092,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":615092,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateProcessManager ] Finished updating entities in ES {\"worker\":\"\",\"peak_memory\":\"99.73 MB\",\"elapsed_seconds\":0.23,\"update_target\":\"activities\",\"should_iterate_again\":false} {\"correlation_id\":\"4ad05333-9afb-492e-9f0f-b2909ac45b32\",\"trace_id\":\"3d8feb24-b173-4158-b0a4-4cf33af85066\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610403,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610403} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610403,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610403,\"participants\":[{\"id\":996282,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996283,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610403,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610403,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610403} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610403,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610403,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610935,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610935} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610935,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610935,\"participants\":[{\"id\":997141,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997142,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610935,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610935,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610935} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610935,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610935,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610470,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610470} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610470,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610470,\"participants\":[{\"id\":996369,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996370,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610470,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610470,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610470} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610470,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610470,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610900,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610900} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610900,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610900,\"participants\":[{\"id\":997081,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997082,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610900,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610900,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610900} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610900,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610900,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614378,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":6167,\"account_id\":null,\"opportunity_id\":null,\"stage_id\":null}} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614378} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614378,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614378,\"participants\":[{\"id\":1002623,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002624,\"user_id\":null,\"contact_id\":6167,\"lead_id\":null},{\"id\":1002625,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"nikolay.nikolov@jiminny.com\",\"domain\":\"jiminny.com\"} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nmalchev@gmail.com\"} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":614378,\"team_id\":2,\"email\":\"nikolay.nikolov@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":614378,\"participants_processed\":3,\"exact_matches\":1,\"domain_matches\":1,\"best_match_found\":true} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614378} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614378,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":614378,\"remote_search\":true,\"lead_id\":null,\"contact_id\":6167,\"account_id\":null,\"opportunity_id\":null,\"stage_id\":null} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612561,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612561} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612561,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612561,\"participants\":[{\"id\":999780,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999781,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612561,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"447700174614.447782589921.OeREojLVnk@txt.staging.jiminny.com\"} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"447700174614.447782589921.OeREojLVnk@txt.staging.jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/447700174614.447782589921.OeREojLVnk%40txt.staging.jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"447700174614.447782589921.OeREojLVnk@txt.staging.jiminny.com\"} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"447700174614.447782589921.OeREojLVnk@txt.staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612561,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612561} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612561,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612561,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612336,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612336} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612336,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612336,\"participants\":[{\"id\":999508,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999509,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999512,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999513,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: ProspectCache - Searching DB for opportunity by owner {\"account_id\":243,\"contact_id\":4491,\"owner_id\":206} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: ProspectCache - Fallback DB opportunity search {\"account_id\":243,\"contact_id\":4491} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: ProspectCache - Opportunity DB search results {\"account_id\":243,\"contact_id\":4491,\"opportunity_id\":276} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612336,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612336,\"participants_processed\":4,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612336} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612336,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612336,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611451,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611451} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611451,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611451,\"participants\":[{\"id\":997955,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997956,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":611451,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":611451,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611451} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611451,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":611451,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"5cd332f8-5b05-4813-bf28-dc3f5c776c31\",\"trace_id\":\"9d576391-5ec6-47d4-9c55-77e4dc0e5881\"}\n[2026-05-11 10:18:21] local.INFO: Running conference:monitor:count command for activities in (2026-05-11 10:16:00, 2026-05-11 10:18:00] {\"correlation_id\":\"5cd332f8-5b05-4813-bf28-dc3f5c776c31\",\"trace_id\":\"9d576391-5ec6-47d4-9c55-77e4dc0e5881\"}\n[2026-05-11 10:18:21] local.INFO: [conference:monitor:count] No activities found in (2026-05-11 10:16:00, 2026-05-11 10:18:00] {\"correlation_id\":\"5cd332f8-5b05-4813-bf28-dc3f5c776c31\",\"trace_id\":\"9d576391-5ec6-47d4-9c55-77e4dc0e5881\"}\n[2026-05-11 10:18:21] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"5cd332f8-5b05-4813-bf28-dc3f5c776c31\",\"trace_id\":\"9d576391-5ec6-47d4-9c55-77e4dc0e5881\"}\n[2026-05-11 10:18:25] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:retry-failed\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"5d165f52-8b9b-49f4-826c-5e6effb36469\",\"trace_id\":\"8d23eb87-94aa-45be-a25c-60adf651f65b\"}\n[2026-05-11 10:18:26] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:retry-failed\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"5d165f52-8b9b-49f4-826c-5e6effb36469\",\"trace_id\":\"8d23eb87-94aa-45be-a25c-60adf651f65b\"}\n[2026-05-11 10:18:26] local.INFO: [ EsUpdateProcessManager ] Finished updating entities in ES {\"worker\":\"\",\"peak_memory\":\"99.73 MB\",\"elapsed_seconds\":0.38,\"update_target\":\"activities\",\"should_iterate_again\":false} {\"correlation_id\":\"4ad05333-9afb-492e-9f0f-b2909ac45b32\",\"trace_id\":\"3d8feb24-b173-4158-b0a4-4cf33af85066\"}\n[2026-05-11 10:19:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"b818863b-2a43-41d9-8ff6-fee7c3d716bc\",\"trace_id\":\"247ba4af-b613-440c-94fe-1c5b9acb9a49\"}\n[2026-05-11 10:19:05] local.INFO: [ScheduleBotCommand] Number of activities to be captured: 0 {\"correlation_id\":\"b818863b-2a43-41d9-8ff6-fee7c3d716bc\",\"trace_id\":\"247ba4af-b613-440c-94fe-1c5b9acb9a49\"}\n[2026-05-11 10:19:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"b818863b-2a43-41d9-8ff6-fee7c3d716bc\",\"trace_id\":\"247ba4af-b613-440c-94fe-1c5b9acb9a49\"}\n[2026-05-11 10:19:07] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"ebc86a92-142f-437d-993d-b5babcf2cc26\",\"trace_id\":\"afbbde14-96ad-42a5-a9b8-acbb3e1d637a\"}\n[2026-05-11 10:19:07] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"ebc86a92-142f-437d-993d-b5babcf2cc26\",\"trace_id\":\"afbbde14-96ad-42a5-a9b8-acbb3e1d637a\"}\n[2026-05-11 10:19:08] local.NOTICE: Monitoring start {\"correlation_id\":\"e77a8f39-a88c-4046-abe4-817093d395f4\",\"trace_id\":\"17ae50a2-26b7-48ab-a9a4-1188e484d567\"}\n[2026-05-11 10:19:08] local.NOTICE: Monitoring end {\"correlation_id\":\"e77a8f39-a88c-4046-abe4-817093d395f4\",\"trace_id\":\"17ae50a2-26b7-48ab-a9a4-1188e484d567\"}\n[2026-05-11 10:19:09] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"82c9f998-b4ec-42a5-9114-b34b4ef4418e\",\"trace_id\":\"398aab71-a970-4adb-bfd2-e7003c988e9b\"}\n[2026-05-11 10:19:09] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"82c9f998-b4ec-42a5-9114-b34b4ef4418e\",\"trace_id\":\"398aab71-a970-4adb-bfd2-e7003c988e9b\"}\n[2026-05-11 10:19:10] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"00ff8a16-df56-4dbe-89ee-949f1fec10ae\",\"trace_id\":\"48f7dab8-39b8-47ff-badc-9e61a319de61\"}\n[2026-05-11 10:19:10] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"00ff8a16-df56-4dbe-89ee-949f1fec10ae\",\"trace_id\":\"48f7dab8-39b8-47ff-badc-9e61a319de61\"}\n[2026-05-11 10:19:10] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"00ff8a16-df56-4dbe-89ee-949f1fec10ae\",\"trace_id\":\"48f7dab8-39b8-47ff-badc-9e61a319de61\"}\n[2026-05-11 10:19:10] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"00ff8a16-df56-4dbe-89ee-949f1fec10ae\",\"trace_id\":\"48f7dab8-39b8-47ff-badc-9e61a319de61\"}","depth":4,"on_screen":true,"value":"[2026-05-11 10:17:03] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":615092,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"f0becb3b-1f4f-4fb3-a311-9056fd2ae449\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:03] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":615092} {\"correlation_id\":\"f0becb3b-1f4f-4fb3-a311-9056fd2ae449\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:03] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":615092,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"f0becb3b-1f4f-4fb3-a311-9056fd2ae449\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:03] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":615092,\"participants\":[{\"id\":1004102,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1004103,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"f0becb3b-1f4f-4fb3-a311-9056fd2ae449\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:03] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"f0becb3b-1f4f-4fb3-a311-9056fd2ae449\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:03] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"f0becb3b-1f4f-4fb3-a311-9056fd2ae449\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:03] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"f0becb3b-1f4f-4fb3-a311-9056fd2ae449\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:03] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"f0becb3b-1f4f-4fb3-a311-9056fd2ae449\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:03] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"f0becb3b-1f4f-4fb3-a311-9056fd2ae449\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:03] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"nikolay.nikolov@jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/nikolay.nikolov%40jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"correlation_id\":\"f0becb3b-1f4f-4fb3-a311-9056fd2ae449\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:03] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"f0becb3b-1f4f-4fb3-a311-9056fd2ae449\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.WARNING: [Hubspot] No retry-after header or policy name found, using default {\"exception_class\":\"SevenShores\\\\Hubspot\\\\Exceptions\\\\BadRequest\"} {\"correlation_id\":\"f0becb3b-1f4f-4fb3-a311-9056fd2ae449\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.WARNING: [Hubspot] Received 429 from API {\"team_id\":2,\"config_id\":2,\"retry_after\":10,\"policy\":null,\"reason\":\"Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response:\n{\\\"status\\\":\\\"error\\\",\\\"message\\\":\\\"You have reached your secondly limit.\\\",\\\"errorType\\\":\\\"RATE_LIMIT\\\",\\\"correlationId\\\":\\\"019e168a-5 (truncated...)\n\"} {\"correlation_id\":\"f0becb3b-1f4f-4fb3-a311-9056fd2ae449\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"f0becb3b-1f4f-4fb3-a311-9056fd2ae449\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614436,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614436} {\"correlation_id\":\"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614436,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614436,\"participants\":[{\"id\":1002751,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002752,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614382,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"78f847cf-6495-4054-b3d4-e179a133bd42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614382} {\"correlation_id\":\"78f847cf-6495-4054-b3d4-e179a133bd42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614382,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"78f847cf-6495-4054-b3d4-e179a133bd42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614382,\"participants\":[{\"id\":1002632,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002633,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"78f847cf-6495-4054-b3d4-e179a133bd42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"78f847cf-6495-4054-b3d4-e179a133bd42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"78f847cf-6495-4054-b3d4-e179a133bd42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"78f847cf-6495-4054-b3d4-e179a133bd42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"78f847cf-6495-4054-b3d4-e179a133bd42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"78f847cf-6495-4054-b3d4-e179a133bd42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"78f847cf-6495-4054-b3d4-e179a133bd42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"78f847cf-6495-4054-b3d4-e179a133bd42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614381,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614381} {\"correlation_id\":\"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614381,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614381,\"participants\":[{\"id\":1002630,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002631,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614378,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":6167,\"account_id\":null,\"opportunity_id\":null,\"stage_id\":null}} {\"correlation_id\":\"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614378} {\"correlation_id\":\"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614378,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614378,\"participants\":[{\"id\":1002623,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002624,\"user_id\":null,\"contact_id\":6167,\"lead_id\":null},{\"id\":1002625,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":15} {\"correlation_id\":\"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613840,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613840} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613840,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613840,\"participants\":[{\"id\":1001764,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1001765,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: ProspectCache - Searching DB for opportunity by owner {\"account_id\":244,\"contact_id\":4487,\"owner_id\":261} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: ProspectCache - Opportunity DB search results {\"account_id\":244,\"contact_id\":4487,\"opportunity_id\":299} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613840,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613840,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613840} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613840,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613840,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613833,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"f9846f48-5841-4a71-b500-64b802c67d05\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613833} {\"correlation_id\":\"f9846f48-5841-4a71-b500-64b802c67d05\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613833,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"f9846f48-5841-4a71-b500-64b802c67d05\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613833,\"participants\":[{\"id\":1001750,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1001751,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"f9846f48-5841-4a71-b500-64b802c67d05\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"f9846f48-5841-4a71-b500-64b802c67d05\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"f9846f48-5841-4a71-b500-64b802c67d05\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"f9846f48-5841-4a71-b500-64b802c67d05\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"f9846f48-5841-4a71-b500-64b802c67d05\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"f9846f48-5841-4a71-b500-64b802c67d05\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613833,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"f9846f48-5841-4a71-b500-64b802c67d05\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613833,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"f9846f48-5841-4a71-b500-64b802c67d05\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613833} {\"correlation_id\":\"f9846f48-5841-4a71-b500-64b802c67d05\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613833,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"f9846f48-5841-4a71-b500-64b802c67d05\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613833,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"f9846f48-5841-4a71-b500-64b802c67d05\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613827,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"d060f13a-e3b7-416c-ac24-ebc305d1fd66\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613827} {\"correlation_id\":\"d060f13a-e3b7-416c-ac24-ebc305d1fd66\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613827,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"d060f13a-e3b7-416c-ac24-ebc305d1fd66\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613827,\"participants\":[{\"id\":1001734,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1001735,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"d060f13a-e3b7-416c-ac24-ebc305d1fd66\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"d060f13a-e3b7-416c-ac24-ebc305d1fd66\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"d060f13a-e3b7-416c-ac24-ebc305d1fd66\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"d060f13a-e3b7-416c-ac24-ebc305d1fd66\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"d060f13a-e3b7-416c-ac24-ebc305d1fd66\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"d060f13a-e3b7-416c-ac24-ebc305d1fd66\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613827,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"d060f13a-e3b7-416c-ac24-ebc305d1fd66\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613827,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"d060f13a-e3b7-416c-ac24-ebc305d1fd66\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613827} {\"correlation_id\":\"d060f13a-e3b7-416c-ac24-ebc305d1fd66\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613827,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"d060f13a-e3b7-416c-ac24-ebc305d1fd66\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613827,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"d060f13a-e3b7-416c-ac24-ebc305d1fd66\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613826,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613826} {\"correlation_id\":\"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613826,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613826,\"participants\":[{\"id\":1001732,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1001733,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613826,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613826,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613826} {\"correlation_id\":\"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613826,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613826,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613820,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"ee78448a-70af-4da3-a3cd-238e2067a49c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613820} {\"correlation_id\":\"ee78448a-70af-4da3-a3cd-238e2067a49c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613820,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"ee78448a-70af-4da3-a3cd-238e2067a49c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613820,\"participants\":[{\"id\":1001721,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1001722,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"ee78448a-70af-4da3-a3cd-238e2067a49c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"ee78448a-70af-4da3-a3cd-238e2067a49c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"ee78448a-70af-4da3-a3cd-238e2067a49c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"ee78448a-70af-4da3-a3cd-238e2067a49c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"ee78448a-70af-4da3-a3cd-238e2067a49c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"ee78448a-70af-4da3-a3cd-238e2067a49c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613820,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"ee78448a-70af-4da3-a3cd-238e2067a49c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613820,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"ee78448a-70af-4da3-a3cd-238e2067a49c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613820} {\"correlation_id\":\"ee78448a-70af-4da3-a3cd-238e2067a49c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613820,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"ee78448a-70af-4da3-a3cd-238e2067a49c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613820,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"ee78448a-70af-4da3-a3cd-238e2067a49c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613818,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"74704a29-86b2-4b3f-ae73-0e6d4ec1891a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613818} {\"correlation_id\":\"74704a29-86b2-4b3f-ae73-0e6d4ec1891a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613818,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"74704a29-86b2-4b3f-ae73-0e6d4ec1891a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613818,\"participants\":[{\"id\":1001717,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1001718,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"74704a29-86b2-4b3f-ae73-0e6d4ec1891a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"74704a29-86b2-4b3f-ae73-0e6d4ec1891a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"74704a29-86b2-4b3f-ae73-0e6d4ec1891a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"74704a29-86b2-4b3f-ae73-0e6d4ec1891a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"74704a29-86b2-4b3f-ae73-0e6d4ec1891a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"74704a29-86b2-4b3f-ae73-0e6d4ec1891a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613818,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"74704a29-86b2-4b3f-ae73-0e6d4ec1891a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613818,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"74704a29-86b2-4b3f-ae73-0e6d4ec1891a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613818} {\"correlation_id\":\"74704a29-86b2-4b3f-ae73-0e6d4ec1891a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613818,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"74704a29-86b2-4b3f-ae73-0e6d4ec1891a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613818,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"74704a29-86b2-4b3f-ae73-0e6d4ec1891a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613812,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"0698152e-ea7b-46d1-95e4-45730b1aac4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613812} {\"correlation_id\":\"0698152e-ea7b-46d1-95e4-45730b1aac4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613812,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"0698152e-ea7b-46d1-95e4-45730b1aac4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613812,\"participants\":[{\"id\":1001705,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1001706,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"0698152e-ea7b-46d1-95e4-45730b1aac4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"0698152e-ea7b-46d1-95e4-45730b1aac4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"0698152e-ea7b-46d1-95e4-45730b1aac4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"0698152e-ea7b-46d1-95e4-45730b1aac4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"0698152e-ea7b-46d1-95e4-45730b1aac4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"0698152e-ea7b-46d1-95e4-45730b1aac4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613812,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"0698152e-ea7b-46d1-95e4-45730b1aac4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613812,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"0698152e-ea7b-46d1-95e4-45730b1aac4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613812} {\"correlation_id\":\"0698152e-ea7b-46d1-95e4-45730b1aac4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613812,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"0698152e-ea7b-46d1-95e4-45730b1aac4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613812,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"0698152e-ea7b-46d1-95e4-45730b1aac4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613807,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4484,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613807} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613807,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613807,\"participants\":[{\"id\":1001690,\"user_id\":253,\"contact_id\":null,\"lead_id\":null},{\"id\":1001691,\"user_id\":null,\"contact_id\":4484,\"lead_id\":null}]} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613807,\"team_id\":2,\"email\":\"preslava.ivanova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: ProspectCache - Searching DB for opportunity by owner {\"account_id\":243,\"contact_id\":4484,\"owner_id\":253} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: ProspectCache - Fallback DB opportunity search {\"account_id\":243,\"contact_id\":4484} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: ProspectCache - Opportunity DB search results {\"account_id\":243,\"contact_id\":4484,\"opportunity_id\":276} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"tsvetomir.banovski@gmail.com\"} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613807,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613807} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613807,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613807,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4484,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613806,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":350,\"stage_id\":34}} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613806} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613806,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613806,\"participants\":[{\"id\":1001688,\"user_id\":253,\"contact_id\":null,\"lead_id\":null},{\"id\":1001689,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null}]} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613806,\"team_id\":2,\"email\":\"preslava.ivanova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: ProspectCache - Searching DB for opportunity by owner {\"account_id\":244,\"contact_id\":4487,\"owner_id\":253} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: ProspectCache - Fallback DB opportunity search {\"account_id\":244,\"contact_id\":4487} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: ProspectCache - Opportunity DB search results {\"account_id\":244,\"contact_id\":4487,\"opportunity_id\":350} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613806,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613806} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613806,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613806,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":350,\"stage_id\":34} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613805,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":350,\"stage_id\":34}} {\"correlation_id\":\"0d5af06d-774a-423e-8566-cb9f43e49711\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613805} {\"correlation_id\":\"0d5af06d-774a-423e-8566-cb9f43e49711\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613805,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"0d5af06d-774a-423e-8566-cb9f43e49711\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613805,\"participants\":[{\"id\":1001686,\"user_id\":253,\"contact_id\":null,\"lead_id\":null},{\"id\":1001687,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null}]} {\"correlation_id\":\"0d5af06d-774a-423e-8566-cb9f43e49711\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"0d5af06d-774a-423e-8566-cb9f43e49711\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"0d5af06d-774a-423e-8566-cb9f43e49711\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"0d5af06d-774a-423e-8566-cb9f43e49711\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"0d5af06d-774a-423e-8566-cb9f43e49711\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613805,\"team_id\":2,\"email\":\"preslava.ivanova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"0d5af06d-774a-423e-8566-cb9f43e49711\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"0d5af06d-774a-423e-8566-cb9f43e49711\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613805,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"0d5af06d-774a-423e-8566-cb9f43e49711\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613805} {\"correlation_id\":\"0d5af06d-774a-423e-8566-cb9f43e49711\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613805,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"0d5af06d-774a-423e-8566-cb9f43e49711\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613805,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":350,\"stage_id\":34} {\"correlation_id\":\"0d5af06d-774a-423e-8566-cb9f43e49711\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613698,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"80021afa-cf61-496e-89ce-8c3e54208849\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613698} {\"correlation_id\":\"80021afa-cf61-496e-89ce-8c3e54208849\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613698,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"80021afa-cf61-496e-89ce-8c3e54208849\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613698,\"participants\":[{\"id\":1001667,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1001668,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"80021afa-cf61-496e-89ce-8c3e54208849\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"80021afa-cf61-496e-89ce-8c3e54208849\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"80021afa-cf61-496e-89ce-8c3e54208849\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"80021afa-cf61-496e-89ce-8c3e54208849\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"80021afa-cf61-496e-89ce-8c3e54208849\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"80021afa-cf61-496e-89ce-8c3e54208849\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613698,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"80021afa-cf61-496e-89ce-8c3e54208849\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613698,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"80021afa-cf61-496e-89ce-8c3e54208849\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613698} {\"correlation_id\":\"80021afa-cf61-496e-89ce-8c3e54208849\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613698,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"80021afa-cf61-496e-89ce-8c3e54208849\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613698,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"80021afa-cf61-496e-89ce-8c3e54208849\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613697,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"26cb04a3-9455-48ca-bbec-d8afcaf66d89\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613697} {\"correlation_id\":\"26cb04a3-9455-48ca-bbec-d8afcaf66d89\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613697,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"26cb04a3-9455-48ca-bbec-d8afcaf66d89\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613697,\"participants\":[{\"id\":1001665,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1001666,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"26cb04a3-9455-48ca-bbec-d8afcaf66d89\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"26cb04a3-9455-48ca-bbec-d8afcaf66d89\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"26cb04a3-9455-48ca-bbec-d8afcaf66d89\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"26cb04a3-9455-48ca-bbec-d8afcaf66d89\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"26cb04a3-9455-48ca-bbec-d8afcaf66d89\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"26cb04a3-9455-48ca-bbec-d8afcaf66d89\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613697,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"26cb04a3-9455-48ca-bbec-d8afcaf66d89\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613697,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"26cb04a3-9455-48ca-bbec-d8afcaf66d89\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613697} {\"correlation_id\":\"26cb04a3-9455-48ca-bbec-d8afcaf66d89\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613697,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"26cb04a3-9455-48ca-bbec-d8afcaf66d89\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613697,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"26cb04a3-9455-48ca-bbec-d8afcaf66d89\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613696,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"1394ff3a-8967-4099-957d-78dd3bd1ad06\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613696} {\"correlation_id\":\"1394ff3a-8967-4099-957d-78dd3bd1ad06\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613696,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"1394ff3a-8967-4099-957d-78dd3bd1ad06\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613696,\"participants\":[{\"id\":1001663,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1001664,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"1394ff3a-8967-4099-957d-78dd3bd1ad06\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"1394ff3a-8967-4099-957d-78dd3bd1ad06\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"1394ff3a-8967-4099-957d-78dd3bd1ad06\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"1394ff3a-8967-4099-957d-78dd3bd1ad06\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"1394ff3a-8967-4099-957d-78dd3bd1ad06\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"1394ff3a-8967-4099-957d-78dd3bd1ad06\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613696,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"1394ff3a-8967-4099-957d-78dd3bd1ad06\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613696,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"1394ff3a-8967-4099-957d-78dd3bd1ad06\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613696} {\"correlation_id\":\"1394ff3a-8967-4099-957d-78dd3bd1ad06\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613696,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"1394ff3a-8967-4099-957d-78dd3bd1ad06\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613696,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"1394ff3a-8967-4099-957d-78dd3bd1ad06\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613695,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"8e71d37f-8fcc-4294-a951-7e7e1fa36414\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613695} {\"correlation_id\":\"8e71d37f-8fcc-4294-a951-7e7e1fa36414\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613695,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"8e71d37f-8fcc-4294-a951-7e7e1fa36414\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613695,\"participants\":[{\"id\":1001661,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1001662,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"8e71d37f-8fcc-4294-a951-7e7e1fa36414\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"8e71d37f-8fcc-4294-a951-7e7e1fa36414\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"8e71d37f-8fcc-4294-a951-7e7e1fa36414\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"8e71d37f-8fcc-4294-a951-7e7e1fa36414\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"8e71d37f-8fcc-4294-a951-7e7e1fa36414\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"8e71d37f-8fcc-4294-a951-7e7e1fa36414\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613695,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"8e71d37f-8fcc-4294-a951-7e7e1fa36414\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613695,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"8e71d37f-8fcc-4294-a951-7e7e1fa36414\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613695} {\"correlation_id\":\"8e71d37f-8fcc-4294-a951-7e7e1fa36414\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613695,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"8e71d37f-8fcc-4294-a951-7e7e1fa36414\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613695,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"8e71d37f-8fcc-4294-a951-7e7e1fa36414\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613694,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"e3d5ac8c-21da-4854-8976-7e5916c19626\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613694} {\"correlation_id\":\"e3d5ac8c-21da-4854-8976-7e5916c19626\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613694,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"e3d5ac8c-21da-4854-8976-7e5916c19626\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613694,\"participants\":[{\"id\":1001659,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1001660,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"e3d5ac8c-21da-4854-8976-7e5916c19626\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"e3d5ac8c-21da-4854-8976-7e5916c19626\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"e3d5ac8c-21da-4854-8976-7e5916c19626\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"e3d5ac8c-21da-4854-8976-7e5916c19626\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"e3d5ac8c-21da-4854-8976-7e5916c19626\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"e3d5ac8c-21da-4854-8976-7e5916c19626\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613694,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"e3d5ac8c-21da-4854-8976-7e5916c19626\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613694,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"e3d5ac8c-21da-4854-8976-7e5916c19626\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613694} {\"correlation_id\":\"e3d5ac8c-21da-4854-8976-7e5916c19626\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613694,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"e3d5ac8c-21da-4854-8976-7e5916c19626\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613694,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"e3d5ac8c-21da-4854-8976-7e5916c19626\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613157,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":350,\"stage_id\":34}} {\"correlation_id\":\"5ac0504a-ec31-4cd3-bee9-a22a17043d87\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613157} {\"correlation_id\":\"5ac0504a-ec31-4cd3-bee9-a22a17043d87\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613157,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"5ac0504a-ec31-4cd3-bee9-a22a17043d87\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613157,\"participants\":[{\"id\":1000746,\"user_id\":253,\"contact_id\":null,\"lead_id\":null},{\"id\":1000747,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null}]} {\"correlation_id\":\"5ac0504a-ec31-4cd3-bee9-a22a17043d87\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"5ac0504a-ec31-4cd3-bee9-a22a17043d87\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"5ac0504a-ec31-4cd3-bee9-a22a17043d87\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"5ac0504a-ec31-4cd3-bee9-a22a17043d87\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"5ac0504a-ec31-4cd3-bee9-a22a17043d87\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613157,\"team_id\":2,\"email\":\"preslava.ivanova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"5ac0504a-ec31-4cd3-bee9-a22a17043d87\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"5ac0504a-ec31-4cd3-bee9-a22a17043d87\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613157,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"5ac0504a-ec31-4cd3-bee9-a22a17043d87\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613157} {\"correlation_id\":\"5ac0504a-ec31-4cd3-bee9-a22a17043d87\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613157,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"5ac0504a-ec31-4cd3-bee9-a22a17043d87\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613157,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":350,\"stage_id\":34} {\"correlation_id\":\"5ac0504a-ec31-4cd3-bee9-a22a17043d87\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613156,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":350,\"stage_id\":34}} {\"correlation_id\":\"dc55bf51-23a4-467e-a0eb-e005ac332df8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613156} {\"correlation_id\":\"dc55bf51-23a4-467e-a0eb-e005ac332df8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613156,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"dc55bf51-23a4-467e-a0eb-e005ac332df8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613156,\"participants\":[{\"id\":1000744,\"user_id\":253,\"contact_id\":null,\"lead_id\":null},{\"id\":1000745,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null}]} {\"correlation_id\":\"dc55bf51-23a4-467e-a0eb-e005ac332df8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"dc55bf51-23a4-467e-a0eb-e005ac332df8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"dc55bf51-23a4-467e-a0eb-e005ac332df8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"dc55bf51-23a4-467e-a0eb-e005ac332df8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"dc55bf51-23a4-467e-a0eb-e005ac332df8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613156,\"team_id\":2,\"email\":\"preslava.ivanova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"dc55bf51-23a4-467e-a0eb-e005ac332df8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"dc55bf51-23a4-467e-a0eb-e005ac332df8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613156,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"dc55bf51-23a4-467e-a0eb-e005ac332df8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613156} {\"correlation_id\":\"dc55bf51-23a4-467e-a0eb-e005ac332df8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613156,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"dc55bf51-23a4-467e-a0eb-e005ac332df8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613156,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":350,\"stage_id\":34} {\"correlation_id\":\"dc55bf51-23a4-467e-a0eb-e005ac332df8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613155,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":350,\"stage_id\":34}} {\"correlation_id\":\"3eef285e-0d37-4ed8-b4ab-aa92cf893970\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613155} {\"correlation_id\":\"3eef285e-0d37-4ed8-b4ab-aa92cf893970\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613155,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"3eef285e-0d37-4ed8-b4ab-aa92cf893970\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613155,\"participants\":[{\"id\":1000742,\"user_id\":253,\"contact_id\":null,\"lead_id\":null},{\"id\":1000743,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null}]} {\"correlation_id\":\"3eef285e-0d37-4ed8-b4ab-aa92cf893970\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"3eef285e-0d37-4ed8-b4ab-aa92cf893970\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"3eef285e-0d37-4ed8-b4ab-aa92cf893970\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"3eef285e-0d37-4ed8-b4ab-aa92cf893970\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"3eef285e-0d37-4ed8-b4ab-aa92cf893970\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613155,\"team_id\":2,\"email\":\"preslava.ivanova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"3eef285e-0d37-4ed8-b4ab-aa92cf893970\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"3eef285e-0d37-4ed8-b4ab-aa92cf893970\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613155,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"3eef285e-0d37-4ed8-b4ab-aa92cf893970\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613155} {\"correlation_id\":\"3eef285e-0d37-4ed8-b4ab-aa92cf893970\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613155,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"3eef285e-0d37-4ed8-b4ab-aa92cf893970\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613155,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":350,\"stage_id\":34} {\"correlation_id\":\"3eef285e-0d37-4ed8-b4ab-aa92cf893970\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613130,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"3c8a085d-bdf1-40eb-a97e-a240a0d42001\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613130} {\"correlation_id\":\"3c8a085d-bdf1-40eb-a97e-a240a0d42001\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613130,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"3c8a085d-bdf1-40eb-a97e-a240a0d42001\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613130,\"participants\":[{\"id\":1000693,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1000694,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"3c8a085d-bdf1-40eb-a97e-a240a0d42001\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"3c8a085d-bdf1-40eb-a97e-a240a0d42001\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"3c8a085d-bdf1-40eb-a97e-a240a0d42001\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"3c8a085d-bdf1-40eb-a97e-a240a0d42001\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"3c8a085d-bdf1-40eb-a97e-a240a0d42001\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"3c8a085d-bdf1-40eb-a97e-a240a0d42001\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613130,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"3c8a085d-bdf1-40eb-a97e-a240a0d42001\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613130,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"3c8a085d-bdf1-40eb-a97e-a240a0d42001\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613130} {\"correlation_id\":\"3c8a085d-bdf1-40eb-a97e-a240a0d42001\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613130,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"3c8a085d-bdf1-40eb-a97e-a240a0d42001\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613130,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"3c8a085d-bdf1-40eb-a97e-a240a0d42001\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612924,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":165,\"stage_id\":89}} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612924} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612924,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612924,\"participants\":[{\"id\":1000290,\"user_id\":19,\"contact_id\":null,\"lead_id\":null},{\"id\":1000291,\"user_id\":null,\"contact_id\":97,\"lead_id\":null}]} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612924,\"team_id\":2,\"email\":\"james.graham@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: ProspectCache - Searching DB for opportunity by owner {\"account_id\":69,\"contact_id\":97,\"owner_id\":19} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: ProspectCache - Opportunity DB search results {\"account_id\":69,\"contact_id\":97,\"opportunity_id\":165} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinsoncrusoe@test.com\"} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612924,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612924} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612924,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612924,\"remote_search\":true,\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":165,\"stage_id\":89} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612923,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":165,\"stage_id\":89}} {\"correlation_id\":\"247ebe62-b545-410c-9a1a-a64a2a16f74f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612923} {\"correlation_id\":\"247ebe62-b545-410c-9a1a-a64a2a16f74f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612923,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"247ebe62-b545-410c-9a1a-a64a2a16f74f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612923,\"participants\":[{\"id\":1000288,\"user_id\":19,\"contact_id\":null,\"lead_id\":null},{\"id\":1000289,\"user_id\":null,\"contact_id\":97,\"lead_id\":null}]} {\"correlation_id\":\"247ebe62-b545-410c-9a1a-a64a2a16f74f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"247ebe62-b545-410c-9a1a-a64a2a16f74f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"247ebe62-b545-410c-9a1a-a64a2a16f74f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"247ebe62-b545-410c-9a1a-a64a2a16f74f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"247ebe62-b545-410c-9a1a-a64a2a16f74f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612923,\"team_id\":2,\"email\":\"james.graham@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"247ebe62-b545-410c-9a1a-a64a2a16f74f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinsoncrusoe@test.com\"} {\"correlation_id\":\"247ebe62-b545-410c-9a1a-a64a2a16f74f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612923,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"247ebe62-b545-410c-9a1a-a64a2a16f74f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612923} {\"correlation_id\":\"247ebe62-b545-410c-9a1a-a64a2a16f74f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612923,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"247ebe62-b545-410c-9a1a-a64a2a16f74f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612923,\"remote_search\":true,\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":165,\"stage_id\":89} {\"correlation_id\":\"247ebe62-b545-410c-9a1a-a64a2a16f74f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612922,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":165,\"stage_id\":89}} {\"correlation_id\":\"8eec93ee-21ff-4839-8d92-4c5e73e5cb02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612922} {\"correlation_id\":\"8eec93ee-21ff-4839-8d92-4c5e73e5cb02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612922,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"8eec93ee-21ff-4839-8d92-4c5e73e5cb02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612922,\"participants\":[{\"id\":1000286,\"user_id\":19,\"contact_id\":null,\"lead_id\":null},{\"id\":1000287,\"user_id\":null,\"contact_id\":97,\"lead_id\":null}]} {\"correlation_id\":\"8eec93ee-21ff-4839-8d92-4c5e73e5cb02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"8eec93ee-21ff-4839-8d92-4c5e73e5cb02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"8eec93ee-21ff-4839-8d92-4c5e73e5cb02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"8eec93ee-21ff-4839-8d92-4c5e73e5cb02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"8eec93ee-21ff-4839-8d92-4c5e73e5cb02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612922,\"team_id\":2,\"email\":\"james.graham@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"8eec93ee-21ff-4839-8d92-4c5e73e5cb02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinsoncrusoe@test.com\"} {\"correlation_id\":\"8eec93ee-21ff-4839-8d92-4c5e73e5cb02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612922,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"8eec93ee-21ff-4839-8d92-4c5e73e5cb02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612922} {\"correlation_id\":\"8eec93ee-21ff-4839-8d92-4c5e73e5cb02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612922,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"8eec93ee-21ff-4839-8d92-4c5e73e5cb02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612922,\"remote_search\":true,\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":165,\"stage_id\":89} {\"correlation_id\":\"8eec93ee-21ff-4839-8d92-4c5e73e5cb02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612847,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"e1add09a-4136-4471-aaab-635ce3913944\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612847} {\"correlation_id\":\"e1add09a-4136-4471-aaab-635ce3913944\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612847,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"e1add09a-4136-4471-aaab-635ce3913944\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612847,\"participants\":[{\"id\":1000130,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1000131,\"user_id\":261,\"contact_id\":null,\"lead_id\":null},{\"id\":1000151,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null}]} {\"correlation_id\":\"e1add09a-4136-4471-aaab-635ce3913944\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"e1add09a-4136-4471-aaab-635ce3913944\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"e1add09a-4136-4471-aaab-635ce3913944\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"e1add09a-4136-4471-aaab-635ce3913944\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"e1add09a-4136-4471-aaab-635ce3913944\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"correlation_id\":\"e1add09a-4136-4471-aaab-635ce3913944\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"adelina.petrova@jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/adelina.petrova%40jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"correlation_id\":\"e1add09a-4136-4471-aaab-635ce3913944\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"correlation_id\":\"e1add09a-4136-4471-aaab-635ce3913944\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"e1add09a-4136-4471-aaab-635ce3913944\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612822,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"0dc18256-a5c4-4809-8f4f-ae8acfa1c62a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612822} {\"correlation_id\":\"0dc18256-a5c4-4809-8f4f-ae8acfa1c62a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612822,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"0dc18256-a5c4-4809-8f4f-ae8acfa1c62a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612822,\"participants\":[{\"id\":1000080,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1000081,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"0dc18256-a5c4-4809-8f4f-ae8acfa1c62a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"0dc18256-a5c4-4809-8f4f-ae8acfa1c62a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"0dc18256-a5c4-4809-8f4f-ae8acfa1c62a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"0dc18256-a5c4-4809-8f4f-ae8acfa1c62a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"0dc18256-a5c4-4809-8f4f-ae8acfa1c62a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"0dc18256-a5c4-4809-8f4f-ae8acfa1c62a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612822,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"0dc18256-a5c4-4809-8f4f-ae8acfa1c62a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612822,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"0dc18256-a5c4-4809-8f4f-ae8acfa1c62a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612822} {\"correlation_id\":\"0dc18256-a5c4-4809-8f4f-ae8acfa1c62a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612822,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"0dc18256-a5c4-4809-8f4f-ae8acfa1c62a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612822,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"0dc18256-a5c4-4809-8f4f-ae8acfa1c62a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612819,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"fc4dcdd9-0121-448e-8b4e-fc0e39d20a72\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612819} {\"correlation_id\":\"fc4dcdd9-0121-448e-8b4e-fc0e39d20a72\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612819,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"fc4dcdd9-0121-448e-8b4e-fc0e39d20a72\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612819,\"participants\":[{\"id\":1000073,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1000074,\"user_id\":261,\"contact_id\":null,\"lead_id\":null},{\"id\":1000075,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"fc4dcdd9-0121-448e-8b4e-fc0e39d20a72\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"fc4dcdd9-0121-448e-8b4e-fc0e39d20a72\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"fc4dcdd9-0121-448e-8b4e-fc0e39d20a72\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"fc4dcdd9-0121-448e-8b4e-fc0e39d20a72\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"fc4dcdd9-0121-448e-8b4e-fc0e39d20a72\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"fc4dcdd9-0121-448e-8b4e-fc0e39d20a72\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612819,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"fc4dcdd9-0121-448e-8b4e-fc0e39d20a72\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"correlation_id\":\"fc4dcdd9-0121-448e-8b4e-fc0e39d20a72\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"correlation_id\":\"fc4dcdd9-0121-448e-8b4e-fc0e39d20a72\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"fc4dcdd9-0121-448e-8b4e-fc0e39d20a72\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612673,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"8b734f7b-ff76-4bcd-b217-f33580cc5d42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612673} {\"correlation_id\":\"8b734f7b-ff76-4bcd-b217-f33580cc5d42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612673,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"8b734f7b-ff76-4bcd-b217-f33580cc5d42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612673,\"participants\":[{\"id\":999993,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":999994,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"8b734f7b-ff76-4bcd-b217-f33580cc5d42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"8b734f7b-ff76-4bcd-b217-f33580cc5d42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"8b734f7b-ff76-4bcd-b217-f33580cc5d42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"8b734f7b-ff76-4bcd-b217-f33580cc5d42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"8b734f7b-ff76-4bcd-b217-f33580cc5d42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"8b734f7b-ff76-4bcd-b217-f33580cc5d42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612673,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"8b734f7b-ff76-4bcd-b217-f33580cc5d42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612673,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"8b734f7b-ff76-4bcd-b217-f33580cc5d42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612673} {\"correlation_id\":\"8b734f7b-ff76-4bcd-b217-f33580cc5d42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612673,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"8b734f7b-ff76-4bcd-b217-f33580cc5d42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612673,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"8b734f7b-ff76-4bcd-b217-f33580cc5d42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612642,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"ba79ca47-b56d-4686-9d40-25f98db53e2d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612642} {\"correlation_id\":\"ba79ca47-b56d-4686-9d40-25f98db53e2d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612642,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"ba79ca47-b56d-4686-9d40-25f98db53e2d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612642,\"participants\":[{\"id\":999935,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":999936,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"ba79ca47-b56d-4686-9d40-25f98db53e2d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"ba79ca47-b56d-4686-9d40-25f98db53e2d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"ba79ca47-b56d-4686-9d40-25f98db53e2d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"ba79ca47-b56d-4686-9d40-25f98db53e2d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"ba79ca47-b56d-4686-9d40-25f98db53e2d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"ba79ca47-b56d-4686-9d40-25f98db53e2d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612642,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"ba79ca47-b56d-4686-9d40-25f98db53e2d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612642,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"ba79ca47-b56d-4686-9d40-25f98db53e2d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612642} {\"correlation_id\":\"ba79ca47-b56d-4686-9d40-25f98db53e2d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612642,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"ba79ca47-b56d-4686-9d40-25f98db53e2d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612642,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"ba79ca47-b56d-4686-9d40-25f98db53e2d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612598,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612598} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612598,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612598,\"participants\":[{\"id\":999857,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999858,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: ProspectCache - Searching DB for opportunity by owner {\"account_id\":243,\"contact_id\":4491,\"owner_id\":206} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: ProspectCache - Fallback DB opportunity search {\"account_id\":243,\"contact_id\":4491} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: ProspectCache - Opportunity DB search results {\"account_id\":243,\"contact_id\":4491,\"opportunity_id\":276} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612598,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612598,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612598} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612598,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612598,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612597,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"62c5275c-1274-41ee-bc3f-5bbf783b9e37\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612597} {\"correlation_id\":\"62c5275c-1274-41ee-bc3f-5bbf783b9e37\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612597,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"62c5275c-1274-41ee-bc3f-5bbf783b9e37\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612597,\"participants\":[{\"id\":999855,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999856,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null}]} {\"correlation_id\":\"62c5275c-1274-41ee-bc3f-5bbf783b9e37\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"62c5275c-1274-41ee-bc3f-5bbf783b9e37\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"62c5275c-1274-41ee-bc3f-5bbf783b9e37\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"62c5275c-1274-41ee-bc3f-5bbf783b9e37\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"62c5275c-1274-41ee-bc3f-5bbf783b9e37\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612597,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"62c5275c-1274-41ee-bc3f-5bbf783b9e37\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"62c5275c-1274-41ee-bc3f-5bbf783b9e37\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612597,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"62c5275c-1274-41ee-bc3f-5bbf783b9e37\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612597} {\"correlation_id\":\"62c5275c-1274-41ee-bc3f-5bbf783b9e37\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612597,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"62c5275c-1274-41ee-bc3f-5bbf783b9e37\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612597,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"62c5275c-1274-41ee-bc3f-5bbf783b9e37\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612596,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"c07694f1-899f-4ac8-be40-e00a204aac88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612596} {\"correlation_id\":\"c07694f1-899f-4ac8-be40-e00a204aac88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612596,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"c07694f1-899f-4ac8-be40-e00a204aac88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612596,\"participants\":[{\"id\":999853,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999854,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null}]} {\"correlation_id\":\"c07694f1-899f-4ac8-be40-e00a204aac88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"c07694f1-899f-4ac8-be40-e00a204aac88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"c07694f1-899f-4ac8-be40-e00a204aac88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"c07694f1-899f-4ac8-be40-e00a204aac88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"c07694f1-899f-4ac8-be40-e00a204aac88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612596,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"c07694f1-899f-4ac8-be40-e00a204aac88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"c07694f1-899f-4ac8-be40-e00a204aac88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612596,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"c07694f1-899f-4ac8-be40-e00a204aac88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612596} {\"correlation_id\":\"c07694f1-899f-4ac8-be40-e00a204aac88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612596,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"c07694f1-899f-4ac8-be40-e00a204aac88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612596,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"c07694f1-899f-4ac8-be40-e00a204aac88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612595,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"a42bd4c7-5a99-40a1-8f2d-310dc2de3d2e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612595} {\"correlation_id\":\"a42bd4c7-5a99-40a1-8f2d-310dc2de3d2e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612595,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"a42bd4c7-5a99-40a1-8f2d-310dc2de3d2e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612595,\"participants\":[{\"id\":999851,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999852,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"a42bd4c7-5a99-40a1-8f2d-310dc2de3d2e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"a42bd4c7-5a99-40a1-8f2d-310dc2de3d2e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"a42bd4c7-5a99-40a1-8f2d-310dc2de3d2e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"a42bd4c7-5a99-40a1-8f2d-310dc2de3d2e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"a42bd4c7-5a99-40a1-8f2d-310dc2de3d2e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"a42bd4c7-5a99-40a1-8f2d-310dc2de3d2e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612595,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"a42bd4c7-5a99-40a1-8f2d-310dc2de3d2e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612595,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"a42bd4c7-5a99-40a1-8f2d-310dc2de3d2e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612595} {\"correlation_id\":\"a42bd4c7-5a99-40a1-8f2d-310dc2de3d2e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612595,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"a42bd4c7-5a99-40a1-8f2d-310dc2de3d2e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612595,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"a42bd4c7-5a99-40a1-8f2d-310dc2de3d2e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612594,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"bb1f8c52-2f4c-4c3b-b77f-4f1a1bb3109d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612594} {\"correlation_id\":\"bb1f8c52-2f4c-4c3b-b77f-4f1a1bb3109d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612594,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"bb1f8c52-2f4c-4c3b-b77f-4f1a1bb3109d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612594,\"participants\":[{\"id\":999849,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999850,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null}]} {\"correlation_id\":\"bb1f8c52-2f4c-4c3b-b77f-4f1a1bb3109d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"bb1f8c52-2f4c-4c3b-b77f-4f1a1bb3109d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"bb1f8c52-2f4c-4c3b-b77f-4f1a1bb3109d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"bb1f8c52-2f4c-4c3b-b77f-4f1a1bb3109d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"bb1f8c52-2f4c-4c3b-b77f-4f1a1bb3109d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612594,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"bb1f8c52-2f4c-4c3b-b77f-4f1a1bb3109d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"bb1f8c52-2f4c-4c3b-b77f-4f1a1bb3109d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612594,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"bb1f8c52-2f4c-4c3b-b77f-4f1a1bb3109d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612594} {\"correlation_id\":\"bb1f8c52-2f4c-4c3b-b77f-4f1a1bb3109d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612594,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"bb1f8c52-2f4c-4c3b-b77f-4f1a1bb3109d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612594,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"bb1f8c52-2f4c-4c3b-b77f-4f1a1bb3109d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612593,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"4d5f5c05-bcfd-478f-aa51-3301a9db49f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612593} {\"correlation_id\":\"4d5f5c05-bcfd-478f-aa51-3301a9db49f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612593,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"4d5f5c05-bcfd-478f-aa51-3301a9db49f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612593,\"participants\":[{\"id\":999847,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999848,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null}]} {\"correlation_id\":\"4d5f5c05-bcfd-478f-aa51-3301a9db49f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4d5f5c05-bcfd-478f-aa51-3301a9db49f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4d5f5c05-bcfd-478f-aa51-3301a9db49f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"4d5f5c05-bcfd-478f-aa51-3301a9db49f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"4d5f5c05-bcfd-478f-aa51-3301a9db49f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612593,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"4d5f5c05-bcfd-478f-aa51-3301a9db49f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"4d5f5c05-bcfd-478f-aa51-3301a9db49f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612593,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"4d5f5c05-bcfd-478f-aa51-3301a9db49f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612593} {\"correlation_id\":\"4d5f5c05-bcfd-478f-aa51-3301a9db49f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612593,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"4d5f5c05-bcfd-478f-aa51-3301a9db49f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612593,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"4d5f5c05-bcfd-478f-aa51-3301a9db49f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612592,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"a80a8412-d94f-42a6-b884-72c206ac1da4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612592} {\"correlation_id\":\"a80a8412-d94f-42a6-b884-72c206ac1da4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612592,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"a80a8412-d94f-42a6-b884-72c206ac1da4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612592,\"participants\":[{\"id\":999845,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999846,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"a80a8412-d94f-42a6-b884-72c206ac1da4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"a80a8412-d94f-42a6-b884-72c206ac1da4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"4a8732a4-99b7-41d1-b7b2-eca5b5e48e29\",\"trace_id\":\"61c44eed-65c5-4e52-a175-3bee690af53c\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"a80a8412-d94f-42a6-b884-72c206ac1da4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"a80a8412-d94f-42a6-b884-72c206ac1da4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"a80a8412-d94f-42a6-b884-72c206ac1da4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"a80a8412-d94f-42a6-b884-72c206ac1da4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612592,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"a80a8412-d94f-42a6-b884-72c206ac1da4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612592,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"a80a8412-d94f-42a6-b884-72c206ac1da4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612592} {\"correlation_id\":\"a80a8412-d94f-42a6-b884-72c206ac1da4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612592,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"a80a8412-d94f-42a6-b884-72c206ac1da4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612592,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"a80a8412-d94f-42a6-b884-72c206ac1da4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ScheduleBotCommand] Number of activities to be captured: 0 {\"correlation_id\":\"4a8732a4-99b7-41d1-b7b2-eca5b5e48e29\",\"trace_id\":\"61c44eed-65c5-4e52-a175-3bee690af53c\"}\n[2026-05-11 10:17:07] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"4a8732a4-99b7-41d1-b7b2-eca5b5e48e29\",\"trace_id\":\"61c44eed-65c5-4e52-a175-3bee690af53c\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612591,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"227671e6-a371-4f4c-b68e-79cfc8a40b80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612591} {\"correlation_id\":\"227671e6-a371-4f4c-b68e-79cfc8a40b80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612591,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"227671e6-a371-4f4c-b68e-79cfc8a40b80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612591,\"participants\":[{\"id\":999843,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999844,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null}]} {\"correlation_id\":\"227671e6-a371-4f4c-b68e-79cfc8a40b80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"227671e6-a371-4f4c-b68e-79cfc8a40b80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"227671e6-a371-4f4c-b68e-79cfc8a40b80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"227671e6-a371-4f4c-b68e-79cfc8a40b80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"227671e6-a371-4f4c-b68e-79cfc8a40b80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612591,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"227671e6-a371-4f4c-b68e-79cfc8a40b80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"227671e6-a371-4f4c-b68e-79cfc8a40b80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612591,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"227671e6-a371-4f4c-b68e-79cfc8a40b80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612591} {\"correlation_id\":\"227671e6-a371-4f4c-b68e-79cfc8a40b80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612591,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"227671e6-a371-4f4c-b68e-79cfc8a40b80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612591,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"227671e6-a371-4f4c-b68e-79cfc8a40b80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612590,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"b0316038-52d2-4649-bbfd-3398e4ba616c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612590} {\"correlation_id\":\"b0316038-52d2-4649-bbfd-3398e4ba616c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612590,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"b0316038-52d2-4649-bbfd-3398e4ba616c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612590,\"participants\":[{\"id\":999841,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999842,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null}]} {\"correlation_id\":\"b0316038-52d2-4649-bbfd-3398e4ba616c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b0316038-52d2-4649-bbfd-3398e4ba616c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b0316038-52d2-4649-bbfd-3398e4ba616c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"b0316038-52d2-4649-bbfd-3398e4ba616c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"b0316038-52d2-4649-bbfd-3398e4ba616c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612590,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"b0316038-52d2-4649-bbfd-3398e4ba616c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"b0316038-52d2-4649-bbfd-3398e4ba616c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612590,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"b0316038-52d2-4649-bbfd-3398e4ba616c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612590} {\"correlation_id\":\"b0316038-52d2-4649-bbfd-3398e4ba616c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612590,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"b0316038-52d2-4649-bbfd-3398e4ba616c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612590,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"b0316038-52d2-4649-bbfd-3398e4ba616c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612589,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"8d0009ec-aa6b-43eb-b5e9-9fdebab1bc88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612589} {\"correlation_id\":\"8d0009ec-aa6b-43eb-b5e9-9fdebab1bc88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612589,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"8d0009ec-aa6b-43eb-b5e9-9fdebab1bc88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612589,\"participants\":[{\"id\":999839,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999840,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null}]} {\"correlation_id\":\"8d0009ec-aa6b-43eb-b5e9-9fdebab1bc88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"8d0009ec-aa6b-43eb-b5e9-9fdebab1bc88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"8d0009ec-aa6b-43eb-b5e9-9fdebab1bc88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"8d0009ec-aa6b-43eb-b5e9-9fdebab1bc88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"8d0009ec-aa6b-43eb-b5e9-9fdebab1bc88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612589,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"8d0009ec-aa6b-43eb-b5e9-9fdebab1bc88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"8d0009ec-aa6b-43eb-b5e9-9fdebab1bc88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612589,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"8d0009ec-aa6b-43eb-b5e9-9fdebab1bc88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612589} {\"correlation_id\":\"8d0009ec-aa6b-43eb-b5e9-9fdebab1bc88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612589,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"8d0009ec-aa6b-43eb-b5e9-9fdebab1bc88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612589,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"8d0009ec-aa6b-43eb-b5e9-9fdebab1bc88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612588,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"3759f33f-9281-45e5-82c7-b8232490ee14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612588} {\"correlation_id\":\"3759f33f-9281-45e5-82c7-b8232490ee14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612588,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"3759f33f-9281-45e5-82c7-b8232490ee14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612588,\"participants\":[{\"id\":999837,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999838,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"3759f33f-9281-45e5-82c7-b8232490ee14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"3759f33f-9281-45e5-82c7-b8232490ee14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"3759f33f-9281-45e5-82c7-b8232490ee14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"3759f33f-9281-45e5-82c7-b8232490ee14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"3759f33f-9281-45e5-82c7-b8232490ee14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"3759f33f-9281-45e5-82c7-b8232490ee14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612588,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"3759f33f-9281-45e5-82c7-b8232490ee14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612588,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"3759f33f-9281-45e5-82c7-b8232490ee14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612588} {\"correlation_id\":\"3759f33f-9281-45e5-82c7-b8232490ee14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612588,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"3759f33f-9281-45e5-82c7-b8232490ee14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612588,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"3759f33f-9281-45e5-82c7-b8232490ee14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612587,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"e1fd0d0c-ddd7-483c-a454-704b27f83a35\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612587} {\"correlation_id\":\"e1fd0d0c-ddd7-483c-a454-704b27f83a35\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612587,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"e1fd0d0c-ddd7-483c-a454-704b27f83a35\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612587,\"participants\":[{\"id\":999835,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999836,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null}]} {\"correlation_id\":\"e1fd0d0c-ddd7-483c-a454-704b27f83a35\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"e1fd0d0c-ddd7-483c-a454-704b27f83a35\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"e1fd0d0c-ddd7-483c-a454-704b27f83a35\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"e1fd0d0c-ddd7-483c-a454-704b27f83a35\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"e1fd0d0c-ddd7-483c-a454-704b27f83a35\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612587,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"e1fd0d0c-ddd7-483c-a454-704b27f83a35\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"e1fd0d0c-ddd7-483c-a454-704b27f83a35\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612587,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"e1fd0d0c-ddd7-483c-a454-704b27f83a35\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612587} {\"correlation_id\":\"e1fd0d0c-ddd7-483c-a454-704b27f83a35\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612587,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"e1fd0d0c-ddd7-483c-a454-704b27f83a35\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612587,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"e1fd0d0c-ddd7-483c-a454-704b27f83a35\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612586,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"65015bee-210a-4abd-ae8e-9b347db68ce5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612586} {\"correlation_id\":\"65015bee-210a-4abd-ae8e-9b347db68ce5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612586,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"65015bee-210a-4abd-ae8e-9b347db68ce5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612586,\"participants\":[{\"id\":999833,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999834,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"65015bee-210a-4abd-ae8e-9b347db68ce5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"65015bee-210a-4abd-ae8e-9b347db68ce5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"65015bee-210a-4abd-ae8e-9b347db68ce5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"65015bee-210a-4abd-ae8e-9b347db68ce5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"65015bee-210a-4abd-ae8e-9b347db68ce5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"65015bee-210a-4abd-ae8e-9b347db68ce5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612586,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"65015bee-210a-4abd-ae8e-9b347db68ce5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612586,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"65015bee-210a-4abd-ae8e-9b347db68ce5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612586} {\"correlation_id\":\"65015bee-210a-4abd-ae8e-9b347db68ce5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612586,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"65015bee-210a-4abd-ae8e-9b347db68ce5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612586,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"65015bee-210a-4abd-ae8e-9b347db68ce5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612585,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"03c44248-e58c-4287-8e6d-5c619c6fb75f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612585} {\"correlation_id\":\"03c44248-e58c-4287-8e6d-5c619c6fb75f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612585,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"03c44248-e58c-4287-8e6d-5c619c6fb75f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612585,\"participants\":[{\"id\":999831,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999832,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null}]} {\"correlation_id\":\"03c44248-e58c-4287-8e6d-5c619c6fb75f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"03c44248-e58c-4287-8e6d-5c619c6fb75f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"03c44248-e58c-4287-8e6d-5c619c6fb75f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"03c44248-e58c-4287-8e6d-5c619c6fb75f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"03c44248-e58c-4287-8e6d-5c619c6fb75f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612585,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"03c44248-e58c-4287-8e6d-5c619c6fb75f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"03c44248-e58c-4287-8e6d-5c619c6fb75f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612585,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"03c44248-e58c-4287-8e6d-5c619c6fb75f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612585} {\"correlation_id\":\"03c44248-e58c-4287-8e6d-5c619c6fb75f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612585,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"03c44248-e58c-4287-8e6d-5c619c6fb75f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612585,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"03c44248-e58c-4287-8e6d-5c619c6fb75f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612584,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"23ed7387-c743-4302-9b44-8d9813be4fe5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612584} {\"correlation_id\":\"23ed7387-c743-4302-9b44-8d9813be4fe5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612584,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"23ed7387-c743-4302-9b44-8d9813be4fe5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612584,\"participants\":[{\"id\":999829,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999830,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null}]} {\"correlation_id\":\"23ed7387-c743-4302-9b44-8d9813be4fe5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"23ed7387-c743-4302-9b44-8d9813be4fe5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"23ed7387-c743-4302-9b44-8d9813be4fe5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"23ed7387-c743-4302-9b44-8d9813be4fe5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"23ed7387-c743-4302-9b44-8d9813be4fe5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612584,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"23ed7387-c743-4302-9b44-8d9813be4fe5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"23ed7387-c743-4302-9b44-8d9813be4fe5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612584,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"23ed7387-c743-4302-9b44-8d9813be4fe5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612584} {\"correlation_id\":\"23ed7387-c743-4302-9b44-8d9813be4fe5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612584,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"23ed7387-c743-4302-9b44-8d9813be4fe5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612584,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"23ed7387-c743-4302-9b44-8d9813be4fe5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612583,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"aeabaf4b-f18e-43fd-aefc-396f54ca6ec9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612583} {\"correlation_id\":\"aeabaf4b-f18e-43fd-aefc-396f54ca6ec9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612583,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"aeabaf4b-f18e-43fd-aefc-396f54ca6ec9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612583,\"participants\":[{\"id\":999827,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999828,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"aeabaf4b-f18e-43fd-aefc-396f54ca6ec9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"aeabaf4b-f18e-43fd-aefc-396f54ca6ec9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"aeabaf4b-f18e-43fd-aefc-396f54ca6ec9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"aeabaf4b-f18e-43fd-aefc-396f54ca6ec9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"aeabaf4b-f18e-43fd-aefc-396f54ca6ec9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"aeabaf4b-f18e-43fd-aefc-396f54ca6ec9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612583,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"aeabaf4b-f18e-43fd-aefc-396f54ca6ec9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612583,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"aeabaf4b-f18e-43fd-aefc-396f54ca6ec9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612583} {\"correlation_id\":\"aeabaf4b-f18e-43fd-aefc-396f54ca6ec9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612583,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"aeabaf4b-f18e-43fd-aefc-396f54ca6ec9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612583,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"aeabaf4b-f18e-43fd-aefc-396f54ca6ec9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612582,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"522ee9f2-8c92-480b-acda-f4759553f0b0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612582} {\"correlation_id\":\"522ee9f2-8c92-480b-acda-f4759553f0b0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612582,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"522ee9f2-8c92-480b-acda-f4759553f0b0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612582,\"participants\":[{\"id\":999825,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999826,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null}]} {\"correlation_id\":\"522ee9f2-8c92-480b-acda-f4759553f0b0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"522ee9f2-8c92-480b-acda-f4759553f0b0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"522ee9f2-8c92-480b-acda-f4759553f0b0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"522ee9f2-8c92-480b-acda-f4759553f0b0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"522ee9f2-8c92-480b-acda-f4759553f0b0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612582,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"522ee9f2-8c92-480b-acda-f4759553f0b0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"522ee9f2-8c92-480b-acda-f4759553f0b0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612582,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"522ee9f2-8c92-480b-acda-f4759553f0b0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612582} {\"correlation_id\":\"522ee9f2-8c92-480b-acda-f4759553f0b0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612582,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"522ee9f2-8c92-480b-acda-f4759553f0b0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612582,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"522ee9f2-8c92-480b-acda-f4759553f0b0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612581,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"8b4434a0-8bca-4ffb-9883-31415fdcd948\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612581} {\"correlation_id\":\"8b4434a0-8bca-4ffb-9883-31415fdcd948\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612581,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"8b4434a0-8bca-4ffb-9883-31415fdcd948\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612581,\"participants\":[{\"id\":999823,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999824,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"8b4434a0-8bca-4ffb-9883-31415fdcd948\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"8b4434a0-8bca-4ffb-9883-31415fdcd948\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"8b4434a0-8bca-4ffb-9883-31415fdcd948\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"8b4434a0-8bca-4ffb-9883-31415fdcd948\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"8b4434a0-8bca-4ffb-9883-31415fdcd948\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"8b4434a0-8bca-4ffb-9883-31415fdcd948\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612581,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"8b4434a0-8bca-4ffb-9883-31415fdcd948\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612581,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"8b4434a0-8bca-4ffb-9883-31415fdcd948\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612581} {\"correlation_id\":\"8b4434a0-8bca-4ffb-9883-31415fdcd948\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612581,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"8b4434a0-8bca-4ffb-9883-31415fdcd948\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612581,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"8b4434a0-8bca-4ffb-9883-31415fdcd948\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612565,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"ff0483e4-50c5-4943-9ac0-1521c68a84a6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612565} {\"correlation_id\":\"ff0483e4-50c5-4943-9ac0-1521c68a84a6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612565,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"ff0483e4-50c5-4943-9ac0-1521c68a84a6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612565,\"participants\":[{\"id\":999789,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999790,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null}]} {\"correlation_id\":\"ff0483e4-50c5-4943-9ac0-1521c68a84a6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"ff0483e4-50c5-4943-9ac0-1521c68a84a6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"ff0483e4-50c5-4943-9ac0-1521c68a84a6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"ff0483e4-50c5-4943-9ac0-1521c68a84a6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"ff0483e4-50c5-4943-9ac0-1521c68a84a6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612565,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"ff0483e4-50c5-4943-9ac0-1521c68a84a6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"ff0483e4-50c5-4943-9ac0-1521c68a84a6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612565,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"ff0483e4-50c5-4943-9ac0-1521c68a84a6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612565} {\"correlation_id\":\"ff0483e4-50c5-4943-9ac0-1521c68a84a6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612565,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"ff0483e4-50c5-4943-9ac0-1521c68a84a6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612565,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"ff0483e4-50c5-4943-9ac0-1521c68a84a6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612563,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":350,\"stage_id\":34}} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612563} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612563,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612563,\"participants\":[{\"id\":999784,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999785,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null}]} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612563,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: ProspectCache - Searching DB for opportunity by owner {\"account_id\":244,\"contact_id\":4487,\"owner_id\":206} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: ProspectCache - Fallback DB opportunity search {\"account_id\":244,\"contact_id\":4487} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: ProspectCache - Opportunity DB search results {\"account_id\":244,\"contact_id\":4487,\"opportunity_id\":350} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612563,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612563} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612563,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612563,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":350,\"stage_id\":34} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612562,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"b3bfac4d-fb8a-4113-a07a-e949910a9e3f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612562} {\"correlation_id\":\"b3bfac4d-fb8a-4113-a07a-e949910a9e3f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612562,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"b3bfac4d-fb8a-4113-a07a-e949910a9e3f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612562,\"participants\":[{\"id\":999782,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999783,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"b3bfac4d-fb8a-4113-a07a-e949910a9e3f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b3bfac4d-fb8a-4113-a07a-e949910a9e3f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b3bfac4d-fb8a-4113-a07a-e949910a9e3f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"b3bfac4d-fb8a-4113-a07a-e949910a9e3f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"b3bfac4d-fb8a-4113-a07a-e949910a9e3f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"correlation_id\":\"b3bfac4d-fb8a-4113-a07a-e949910a9e3f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"447782589921@txt.staging.jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/447782589921%40txt.staging.jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"correlation_id\":\"b3bfac4d-fb8a-4113-a07a-e949910a9e3f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"correlation_id\":\"b3bfac4d-fb8a-4113-a07a-e949910a9e3f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":10} {\"correlation_id\":\"b3bfac4d-fb8a-4113-a07a-e949910a9e3f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612561,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"093de884-5d00-46dd-8202-1f6294142ac4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612561} {\"correlation_id\":\"093de884-5d00-46dd-8202-1f6294142ac4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612561,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"093de884-5d00-46dd-8202-1f6294142ac4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612561,\"participants\":[{\"id\":999780,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999781,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"093de884-5d00-46dd-8202-1f6294142ac4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"093de884-5d00-46dd-8202-1f6294142ac4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"093de884-5d00-46dd-8202-1f6294142ac4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"093de884-5d00-46dd-8202-1f6294142ac4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"093de884-5d00-46dd-8202-1f6294142ac4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612561,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"093de884-5d00-46dd-8202-1f6294142ac4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"447700174614.447782589921.OeREojLVnk@txt.staging.jiminny.com\"} {\"correlation_id\":\"093de884-5d00-46dd-8202-1f6294142ac4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:11] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"447700174614.447782589921.OeREojLVnk@txt.staging.jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/447700174614.447782589921.OeREojLVnk%40txt.staging.jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"correlation_id\":\"093de884-5d00-46dd-8202-1f6294142ac4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:11] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"447700174614.447782589921.OeREojLVnk@txt.staging.jiminny.com\"} {\"correlation_id\":\"093de884-5d00-46dd-8202-1f6294142ac4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:11] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":13} {\"correlation_id\":\"093de884-5d00-46dd-8202-1f6294142ac4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:12] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612560,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"55d42510-0a7f-49da-92bb-3d7d04f519e0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:12] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612560} {\"correlation_id\":\"55d42510-0a7f-49da-92bb-3d7d04f519e0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:12] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612560,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"55d42510-0a7f-49da-92bb-3d7d04f519e0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:12] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612560,\"participants\":[{\"id\":999778,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999779,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"55d42510-0a7f-49da-92bb-3d7d04f519e0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:12] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"55d42510-0a7f-49da-92bb-3d7d04f519e0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:12] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"55d42510-0a7f-49da-92bb-3d7d04f519e0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:12] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"55d42510-0a7f-49da-92bb-3d7d04f519e0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:12] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"55d42510-0a7f-49da-92bb-3d7d04f519e0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:12] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"correlation_id\":\"55d42510-0a7f-49da-92bb-3d7d04f519e0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:12] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"correlation_id\":\"55d42510-0a7f-49da-92bb-3d7d04f519e0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:12] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"55d42510-0a7f-49da-92bb-3d7d04f519e0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612559,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34}} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612559} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612559,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612559,\"participants\":[{\"id\":999776,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999777,\"user_id\":null,\"contact_id\":97,\"lead_id\":null}]} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612559,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: ProspectCache - Searching DB for opportunity by owner {\"account_id\":69,\"contact_id\":97,\"owner_id\":206} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: ProspectCache - Fallback DB opportunity search {\"account_id\":69,\"contact_id\":97} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: ProspectCache - Opportunity DB search results {\"account_id\":69,\"contact_id\":97,\"opportunity_id\":5011} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinsoncrusoe@test.com\"} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612559,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612559} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612559,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612559,\"remote_search\":true,\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:14] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612558,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34}} {\"correlation_id\":\"87d35b30-46fd-4cbe-815e-3c7fc0873c55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:14] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612558} {\"correlation_id\":\"87d35b30-46fd-4cbe-815e-3c7fc0873c55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:14] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612558,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"87d35b30-46fd-4cbe-815e-3c7fc0873c55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:14] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612558,\"participants\":[{\"id\":999774,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999775,\"user_id\":null,\"contact_id\":97,\"lead_id\":null}]} {\"correlation_id\":\"87d35b30-46fd-4cbe-815e-3c7fc0873c55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:14] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"87d35b30-46fd-4cbe-815e-3c7fc0873c55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:14] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"87d35b30-46fd-4cbe-815e-3c7fc0873c55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:14] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"87d35b30-46fd-4cbe-815e-3c7fc0873c55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:14] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"87d35b30-46fd-4cbe-815e-3c7fc0873c55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:14] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612558,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"87d35b30-46fd-4cbe-815e-3c7fc0873c55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:14] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinsoncrusoe@test.com\"} {\"correlation_id\":\"87d35b30-46fd-4cbe-815e-3c7fc0873c55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:14] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612558,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"87d35b30-46fd-4cbe-815e-3c7fc0873c55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:14] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612558} {\"correlation_id\":\"87d35b30-46fd-4cbe-815e-3c7fc0873c55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:14] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612558,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"87d35b30-46fd-4cbe-815e-3c7fc0873c55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:14] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612558,\"remote_search\":true,\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34} {\"correlation_id\":\"87d35b30-46fd-4cbe-815e-3c7fc0873c55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:15] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612557,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34}} {\"correlation_id\":\"f4441c9e-1575-406a-9087-739d00f7051a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:15] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612557} {\"correlation_id\":\"f4441c9e-1575-406a-9087-739d00f7051a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:15] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612557,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"f4441c9e-1575-406a-9087-739d00f7051a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:15] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612557,\"participants\":[{\"id\":999772,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999773,\"user_id\":null,\"contact_id\":97,\"lead_id\":null}]} {\"correlation_id\":\"f4441c9e-1575-406a-9087-739d00f7051a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:16] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"f4441c9e-1575-406a-9087-739d00f7051a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:16] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"f4441c9e-1575-406a-9087-739d00f7051a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:16] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"f4441c9e-1575-406a-9087-739d00f7051a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:16] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"f4441c9e-1575-406a-9087-739d00f7051a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:16] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612557,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"f4441c9e-1575-406a-9087-739d00f7051a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:16] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinsoncrusoe@test.com\"} {\"correlation_id\":\"f4441c9e-1575-406a-9087-739d00f7051a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:16] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612557,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"f4441c9e-1575-406a-9087-739d00f7051a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:16] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612557} {\"correlation_id\":\"f4441c9e-1575-406a-9087-739d00f7051a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:16] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612557,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"f4441c9e-1575-406a-9087-739d00f7051a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:16] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612557,\"remote_search\":true,\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34} {\"correlation_id\":\"f4441c9e-1575-406a-9087-739d00f7051a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:17] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612556,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34}} {\"correlation_id\":\"0c63e1d6-a318-43c2-8cc4-a2e00c5260e3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:17] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612556} {\"correlation_id\":\"0c63e1d6-a318-43c2-8cc4-a2e00c5260e3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:17] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612556,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"0c63e1d6-a318-43c2-8cc4-a2e00c5260e3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:17] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612556,\"participants\":[{\"id\":999770,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999771,\"user_id\":null,\"contact_id\":97,\"lead_id\":null}]} {\"correlation_id\":\"0c63e1d6-a318-43c2-8cc4-a2e00c5260e3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:17] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"0c63e1d6-a318-43c2-8cc4-a2e00c5260e3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:17] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"0c63e1d6-a318-43c2-8cc4-a2e00c5260e3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:17] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"0c63e1d6-a318-43c2-8cc4-a2e00c5260e3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:17] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"0c63e1d6-a318-43c2-8cc4-a2e00c5260e3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:17] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612556,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"0c63e1d6-a318-43c2-8cc4-a2e00c5260e3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:17] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinsoncrusoe@test.com\"} {\"correlation_id\":\"0c63e1d6-a318-43c2-8cc4-a2e00c5260e3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:17] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612556,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"0c63e1d6-a318-43c2-8cc4-a2e00c5260e3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:17] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612556} {\"correlation_id\":\"0c63e1d6-a318-43c2-8cc4-a2e00c5260e3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:17] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612556,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"0c63e1d6-a318-43c2-8cc4-a2e00c5260e3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:17] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612556,\"remote_search\":true,\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34} {\"correlation_id\":\"0c63e1d6-a318-43c2-8cc4-a2e00c5260e3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:17] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612555,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34}} {\"correlation_id\":\"3268196e-0a93-4fd3-a61b-5dfcc3e560a8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:18] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612555} {\"correlation_id\":\"3268196e-0a93-4fd3-a61b-5dfcc3e560a8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:18] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612555,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"3268196e-0a93-4fd3-a61b-5dfcc3e560a8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:18] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612555,\"participants\":[{\"id\":999768,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999769,\"user_id\":null,\"contact_id\":97,\"lead_id\":null}]} {\"correlation_id\":\"3268196e-0a93-4fd3-a61b-5dfcc3e560a8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:18] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"3268196e-0a93-4fd3-a61b-5dfcc3e560a8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:18] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"3268196e-0a93-4fd3-a61b-5dfcc3e560a8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:18] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"3268196e-0a93-4fd3-a61b-5dfcc3e560a8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:18] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"3268196e-0a93-4fd3-a61b-5dfcc3e560a8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:18] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612555,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"3268196e-0a93-4fd3-a61b-5dfcc3e560a8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:18] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinsoncrusoe@test.com\"} {\"correlation_id\":\"3268196e-0a93-4fd3-a61b-5dfcc3e560a8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:18] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612555,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"3268196e-0a93-4fd3-a61b-5dfcc3e560a8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:18] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612555} {\"correlation_id\":\"3268196e-0a93-4fd3-a61b-5dfcc3e560a8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:18] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612555,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"3268196e-0a93-4fd3-a61b-5dfcc3e560a8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612555,\"remote_search\":true,\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34} {\"correlation_id\":\"3268196e-0a93-4fd3-a61b-5dfcc3e560a8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [ EsUpdateProcessManager ] Finished updating entities in ES {\"worker\":\"\",\"peak_memory\":\"99.73 MB\",\"elapsed_seconds\":11.49,\"update_target\":\"activities\",\"should_iterate_again\":false} {\"correlation_id\":\"4ad05333-9afb-492e-9f0f-b2909ac45b32\",\"trace_id\":\"3d8feb24-b173-4158-b0a4-4cf33af85066\"}\n[2026-05-11 10:17:19] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612554,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34}} {\"correlation_id\":\"09a1bea2-5b92-4a89-8617-bc5809db48d1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612554} {\"correlation_id\":\"09a1bea2-5b92-4a89-8617-bc5809db48d1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612554,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"09a1bea2-5b92-4a89-8617-bc5809db48d1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612554,\"participants\":[{\"id\":999766,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999767,\"user_id\":null,\"contact_id\":97,\"lead_id\":null}]} {\"correlation_id\":\"09a1bea2-5b92-4a89-8617-bc5809db48d1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"09a1bea2-5b92-4a89-8617-bc5809db48d1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"09a1bea2-5b92-4a89-8617-bc5809db48d1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"09a1bea2-5b92-4a89-8617-bc5809db48d1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"09a1bea2-5b92-4a89-8617-bc5809db48d1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612554,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"09a1bea2-5b92-4a89-8617-bc5809db48d1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinsoncrusoe@test.com\"} {\"correlation_id\":\"09a1bea2-5b92-4a89-8617-bc5809db48d1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612554,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"09a1bea2-5b92-4a89-8617-bc5809db48d1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612554} {\"correlation_id\":\"09a1bea2-5b92-4a89-8617-bc5809db48d1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612554,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"09a1bea2-5b92-4a89-8617-bc5809db48d1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612554,\"remote_search\":true,\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34} {\"correlation_id\":\"09a1bea2-5b92-4a89-8617-bc5809db48d1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612553,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34}} {\"correlation_id\":\"40b197d4-a099-4e5a-9b85-7d5e01a97d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612553} {\"correlation_id\":\"40b197d4-a099-4e5a-9b85-7d5e01a97d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612553,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"40b197d4-a099-4e5a-9b85-7d5e01a97d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612553,\"participants\":[{\"id\":999764,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999765,\"user_id\":null,\"contact_id\":97,\"lead_id\":null}]} {\"correlation_id\":\"40b197d4-a099-4e5a-9b85-7d5e01a97d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"40b197d4-a099-4e5a-9b85-7d5e01a97d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"40b197d4-a099-4e5a-9b85-7d5e01a97d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"40b197d4-a099-4e5a-9b85-7d5e01a97d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"40b197d4-a099-4e5a-9b85-7d5e01a97d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612553,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"40b197d4-a099-4e5a-9b85-7d5e01a97d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinsoncrusoe@test.com\"} {\"correlation_id\":\"40b197d4-a099-4e5a-9b85-7d5e01a97d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612553,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"40b197d4-a099-4e5a-9b85-7d5e01a97d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612553} {\"correlation_id\":\"40b197d4-a099-4e5a-9b85-7d5e01a97d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612553,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"40b197d4-a099-4e5a-9b85-7d5e01a97d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612553,\"remote_search\":true,\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34} {\"correlation_id\":\"40b197d4-a099-4e5a-9b85-7d5e01a97d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612552,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34}} {\"correlation_id\":\"6548c611-b94a-40c9-8a0e-d3c24ba47072\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612552} {\"correlation_id\":\"6548c611-b94a-40c9-8a0e-d3c24ba47072\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612552,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"6548c611-b94a-40c9-8a0e-d3c24ba47072\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612552,\"participants\":[{\"id\":999762,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999763,\"user_id\":null,\"contact_id\":97,\"lead_id\":null}]} {\"correlation_id\":\"6548c611-b94a-40c9-8a0e-d3c24ba47072\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"6548c611-b94a-40c9-8a0e-d3c24ba47072\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"6548c611-b94a-40c9-8a0e-d3c24ba47072\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6548c611-b94a-40c9-8a0e-d3c24ba47072\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"6548c611-b94a-40c9-8a0e-d3c24ba47072\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612552,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"6548c611-b94a-40c9-8a0e-d3c24ba47072\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinsoncrusoe@test.com\"} {\"correlation_id\":\"6548c611-b94a-40c9-8a0e-d3c24ba47072\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612552,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"6548c611-b94a-40c9-8a0e-d3c24ba47072\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612552} {\"correlation_id\":\"6548c611-b94a-40c9-8a0e-d3c24ba47072\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612552,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"6548c611-b94a-40c9-8a0e-d3c24ba47072\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612552,\"remote_search\":true,\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34} {\"correlation_id\":\"6548c611-b94a-40c9-8a0e-d3c24ba47072\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612551,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34}} {\"correlation_id\":\"4cce51ee-846b-43b2-a0cd-d83dc5eff920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612551} {\"correlation_id\":\"4cce51ee-846b-43b2-a0cd-d83dc5eff920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612551,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"4cce51ee-846b-43b2-a0cd-d83dc5eff920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612551,\"participants\":[{\"id\":999760,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999761,\"user_id\":null,\"contact_id\":97,\"lead_id\":null}]} {\"correlation_id\":\"4cce51ee-846b-43b2-a0cd-d83dc5eff920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4cce51ee-846b-43b2-a0cd-d83dc5eff920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4cce51ee-846b-43b2-a0cd-d83dc5eff920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"4cce51ee-846b-43b2-a0cd-d83dc5eff920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"4cce51ee-846b-43b2-a0cd-d83dc5eff920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612551,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"4cce51ee-846b-43b2-a0cd-d83dc5eff920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinsoncrusoe@test.com\"} {\"correlation_id\":\"4cce51ee-846b-43b2-a0cd-d83dc5eff920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612551,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"4cce51ee-846b-43b2-a0cd-d83dc5eff920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612551} {\"correlation_id\":\"4cce51ee-846b-43b2-a0cd-d83dc5eff920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612551,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"4cce51ee-846b-43b2-a0cd-d83dc5eff920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612551,\"remote_search\":true,\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34} {\"correlation_id\":\"4cce51ee-846b-43b2-a0cd-d83dc5eff920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612550,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34}} {\"correlation_id\":\"b0e6efce-5447-4d7d-be32-a4dfafa64fdc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612550} {\"correlation_id\":\"b0e6efce-5447-4d7d-be32-a4dfafa64fdc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612550,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"b0e6efce-5447-4d7d-be32-a4dfafa64fdc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612550,\"participants\":[{\"id\":999758,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999759,\"user_id\":null,\"contact_id\":97,\"lead_id\":null}]} {\"correlation_id\":\"b0e6efce-5447-4d7d-be32-a4dfafa64fdc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b0e6efce-5447-4d7d-be32-a4dfafa64fdc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b0e6efce-5447-4d7d-be32-a4dfafa64fdc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"b0e6efce-5447-4d7d-be32-a4dfafa64fdc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"b0e6efce-5447-4d7d-be32-a4dfafa64fdc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612550,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"b0e6efce-5447-4d7d-be32-a4dfafa64fdc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinsoncrusoe@test.com\"} {\"correlation_id\":\"b0e6efce-5447-4d7d-be32-a4dfafa64fdc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612550,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"b0e6efce-5447-4d7d-be32-a4dfafa64fdc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612550} {\"correlation_id\":\"b0e6efce-5447-4d7d-be32-a4dfafa64fdc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612550,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"b0e6efce-5447-4d7d-be32-a4dfafa64fdc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612550,\"remote_search\":true,\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34} {\"correlation_id\":\"b0e6efce-5447-4d7d-be32-a4dfafa64fdc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612549,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34}} {\"correlation_id\":\"e8c5b540-3796-4bed-b52c-3f7a6b7586aa\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612549} {\"correlation_id\":\"e8c5b540-3796-4bed-b52c-3f7a6b7586aa\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612549,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"e8c5b540-3796-4bed-b52c-3f7a6b7586aa\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612549,\"participants\":[{\"id\":999756,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999757,\"user_id\":null,\"contact_id\":97,\"lead_id\":null}]} {\"correlation_id\":\"e8c5b540-3796-4bed-b52c-3f7a6b7586aa\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"e8c5b540-3796-4bed-b52c-3f7a6b7586aa\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"e8c5b540-3796-4bed-b52c-3f7a6b7586aa\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"e8c5b540-3796-4bed-b52c-3f7a6b7586aa\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"e8c5b540-3796-4bed-b52c-3f7a6b7586aa\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612549,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"e8c5b540-3796-4bed-b52c-3f7a6b7586aa\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinsoncrusoe@test.com\"} {\"correlation_id\":\"e8c5b540-3796-4bed-b52c-3f7a6b7586aa\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612549,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"e8c5b540-3796-4bed-b52c-3f7a6b7586aa\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612549} {\"correlation_id\":\"e8c5b540-3796-4bed-b52c-3f7a6b7586aa\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612549,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"e8c5b540-3796-4bed-b52c-3f7a6b7586aa\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612549,\"remote_search\":true,\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34} {\"correlation_id\":\"e8c5b540-3796-4bed-b52c-3f7a6b7586aa\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612365,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"e5125373-9a81-49ac-ab11-5aebfe6aea74\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612365} {\"correlation_id\":\"e5125373-9a81-49ac-ab11-5aebfe6aea74\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612365,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"e5125373-9a81-49ac-ab11-5aebfe6aea74\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612365,\"participants\":[{\"id\":999563,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999564,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"e5125373-9a81-49ac-ab11-5aebfe6aea74\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"e5125373-9a81-49ac-ab11-5aebfe6aea74\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"e5125373-9a81-49ac-ab11-5aebfe6aea74\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"e5125373-9a81-49ac-ab11-5aebfe6aea74\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"e5125373-9a81-49ac-ab11-5aebfe6aea74\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"e5125373-9a81-49ac-ab11-5aebfe6aea74\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612365,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"e5125373-9a81-49ac-ab11-5aebfe6aea74\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612365,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"e5125373-9a81-49ac-ab11-5aebfe6aea74\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612365} {\"correlation_id\":\"e5125373-9a81-49ac-ab11-5aebfe6aea74\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612365,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"e5125373-9a81-49ac-ab11-5aebfe6aea74\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612365,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"e5125373-9a81-49ac-ab11-5aebfe6aea74\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:22] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612360,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"611796ed-b766-420d-a544-4fdb1123b4f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:22] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612360} {\"correlation_id\":\"611796ed-b766-420d-a544-4fdb1123b4f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:22] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612360,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"611796ed-b766-420d-a544-4fdb1123b4f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:22] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612360,\"participants\":[{\"id\":999552,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999553,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999565,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"611796ed-b766-420d-a544-4fdb1123b4f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:22] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"611796ed-b766-420d-a544-4fdb1123b4f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:22] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"611796ed-b766-420d-a544-4fdb1123b4f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:22] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"611796ed-b766-420d-a544-4fdb1123b4f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:22] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"611796ed-b766-420d-a544-4fdb1123b4f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:22] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"611796ed-b766-420d-a544-4fdb1123b4f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:22] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612360,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"611796ed-b766-420d-a544-4fdb1123b4f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:22] local.WARNING: [Hubspot] No retry-after header or policy name found, using default {\"exception_class\":\"SevenShores\\\\Hubspot\\\\Exceptions\\\\BadRequest\"} {\"correlation_id\":\"611796ed-b766-420d-a544-4fdb1123b4f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:22] local.WARNING: [Hubspot] Received 429 from API {\"team_id\":2,\"config_id\":2,\"retry_after\":10,\"policy\":null,\"reason\":\"Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response:\n{\\\"status\\\":\\\"error\\\",\\\"message\\\":\\\"You have reached your secondly limit.\\\",\\\"errorType\\\":\\\"RATE_LIMIT\\\",\\\"correlationId\\\":\\\"019e168a-9 (truncated...)\n\"} {\"correlation_id\":\"611796ed-b766-420d-a544-4fdb1123b4f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:22] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":12} {\"correlation_id\":\"611796ed-b766-420d-a544-4fdb1123b4f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:23] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612340,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"f69192c9-9ba8-48e0-b614-996bf3dcc7d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:23] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612340} {\"correlation_id\":\"f69192c9-9ba8-48e0-b614-996bf3dcc7d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:23] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612340,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"f69192c9-9ba8-48e0-b614-996bf3dcc7d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:23] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612340,\"participants\":[{\"id\":999516,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999517,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999518,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999519,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"f69192c9-9ba8-48e0-b614-996bf3dcc7d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:23] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"f69192c9-9ba8-48e0-b614-996bf3dcc7d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:23] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"f69192c9-9ba8-48e0-b614-996bf3dcc7d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:23] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"f69192c9-9ba8-48e0-b614-996bf3dcc7d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:23] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"f69192c9-9ba8-48e0-b614-996bf3dcc7d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:23] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"f69192c9-9ba8-48e0-b614-996bf3dcc7d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:23] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612340,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"f69192c9-9ba8-48e0-b614-996bf3dcc7d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:23] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"f69192c9-9ba8-48e0-b614-996bf3dcc7d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:23] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612339,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"6522d428-c400-448c-9130-a06133b21471\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:23] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612339} {\"correlation_id\":\"6522d428-c400-448c-9130-a06133b21471\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612339,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"6522d428-c400-448c-9130-a06133b21471\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612339,\"participants\":[{\"id\":999514,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999515,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999540,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"6522d428-c400-448c-9130-a06133b21471\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"6522d428-c400-448c-9130-a06133b21471\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"6522d428-c400-448c-9130-a06133b21471\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6522d428-c400-448c-9130-a06133b21471\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"6522d428-c400-448c-9130-a06133b21471\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"6522d428-c400-448c-9130-a06133b21471\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612339,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"6522d428-c400-448c-9130-a06133b21471\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"6522d428-c400-448c-9130-a06133b21471\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612336,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"0588c797-4ae0-4d7b-b3ee-9706e7ef39df\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612336} {\"correlation_id\":\"0588c797-4ae0-4d7b-b3ee-9706e7ef39df\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612336,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"0588c797-4ae0-4d7b-b3ee-9706e7ef39df\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612336,\"participants\":[{\"id\":999508,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999509,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999512,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999513,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"0588c797-4ae0-4d7b-b3ee-9706e7ef39df\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"0588c797-4ae0-4d7b-b3ee-9706e7ef39df\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"0588c797-4ae0-4d7b-b3ee-9706e7ef39df\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"0588c797-4ae0-4d7b-b3ee-9706e7ef39df\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"0588c797-4ae0-4d7b-b3ee-9706e7ef39df\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"0588c797-4ae0-4d7b-b3ee-9706e7ef39df\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612336,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"0588c797-4ae0-4d7b-b3ee-9706e7ef39df\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":15} {\"correlation_id\":\"0588c797-4ae0-4d7b-b3ee-9706e7ef39df\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612183,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"946c4e96-6983-445b-a842-b212439024fd\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612183} {\"correlation_id\":\"946c4e96-6983-445b-a842-b212439024fd\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612183,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"946c4e96-6983-445b-a842-b212439024fd\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612183,\"participants\":[{\"id\":999227,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":999228,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"946c4e96-6983-445b-a842-b212439024fd\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"946c4e96-6983-445b-a842-b212439024fd\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"946c4e96-6983-445b-a842-b212439024fd\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"946c4e96-6983-445b-a842-b212439024fd\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"946c4e96-6983-445b-a842-b212439024fd\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"946c4e96-6983-445b-a842-b212439024fd\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612183,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"946c4e96-6983-445b-a842-b212439024fd\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612183,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"946c4e96-6983-445b-a842-b212439024fd\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612183} {\"correlation_id\":\"946c4e96-6983-445b-a842-b212439024fd\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612183,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"946c4e96-6983-445b-a842-b212439024fd\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612183,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"946c4e96-6983-445b-a842-b212439024fd\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612182,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"f5eaabe1-ed2b-4779-8907-9a7cb181c90e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612182} {\"correlation_id\":\"f5eaabe1-ed2b-4779-8907-9a7cb181c90e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612182,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"f5eaabe1-ed2b-4779-8907-9a7cb181c90e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612182,\"participants\":[{\"id\":999225,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":999226,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"f5eaabe1-ed2b-4779-8907-9a7cb181c90e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"f5eaabe1-ed2b-4779-8907-9a7cb181c90e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"f5eaabe1-ed2b-4779-8907-9a7cb181c90e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"f5eaabe1-ed2b-4779-8907-9a7cb181c90e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"f5eaabe1-ed2b-4779-8907-9a7cb181c90e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"f5eaabe1-ed2b-4779-8907-9a7cb181c90e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612182,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"f5eaabe1-ed2b-4779-8907-9a7cb181c90e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612182,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"f5eaabe1-ed2b-4779-8907-9a7cb181c90e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612182} {\"correlation_id\":\"f5eaabe1-ed2b-4779-8907-9a7cb181c90e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612182,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"f5eaabe1-ed2b-4779-8907-9a7cb181c90e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612182,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"f5eaabe1-ed2b-4779-8907-9a7cb181c90e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"86d5bdfe-cc94-41f2-94ba-422242e4e1f5\",\"trace_id\":\"659a90d1-e357-4e8c-a391-979e687c5ae4\"}\n[2026-05-11 10:17:25] local.INFO: [ EsUpdateProcessManager ] Finished updating entities in ES {\"worker\":\"\",\"peak_memory\":\"99.73 MB\",\"elapsed_seconds\":1.26,\"update_target\":\"activities\",\"should_iterate_again\":false} {\"correlation_id\":\"4ad05333-9afb-492e-9f0f-b2909ac45b32\",\"trace_id\":\"3d8feb24-b173-4158-b0a4-4cf33af85066\"}\n[2026-05-11 10:17:25] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612181,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"d2216c54-0324-4668-a561-66c972bd24b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612181} {\"correlation_id\":\"d2216c54-0324-4668-a561-66c972bd24b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612181,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"d2216c54-0324-4668-a561-66c972bd24b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612181,\"participants\":[{\"id\":999223,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":999224,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"d2216c54-0324-4668-a561-66c972bd24b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"d2216c54-0324-4668-a561-66c972bd24b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"d2216c54-0324-4668-a561-66c972bd24b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"d2216c54-0324-4668-a561-66c972bd24b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"d2216c54-0324-4668-a561-66c972bd24b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"d2216c54-0324-4668-a561-66c972bd24b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"86d5bdfe-cc94-41f2-94ba-422242e4e1f5\",\"trace_id\":\"659a90d1-e357-4e8c-a391-979e687c5ae4\"}\n[2026-05-11 10:17:25] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612181,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"d2216c54-0324-4668-a561-66c972bd24b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612181,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"d2216c54-0324-4668-a561-66c972bd24b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612181} {\"correlation_id\":\"d2216c54-0324-4668-a561-66c972bd24b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612181,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"d2216c54-0324-4668-a561-66c972bd24b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612181,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"d2216c54-0324-4668-a561-66c972bd24b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612180,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"f8c127c2-60ef-47b1-b0e2-5adb2b6d7349\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612180} {\"correlation_id\":\"f8c127c2-60ef-47b1-b0e2-5adb2b6d7349\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612180,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"f8c127c2-60ef-47b1-b0e2-5adb2b6d7349\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612180,\"participants\":[{\"id\":999221,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":999222,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"f8c127c2-60ef-47b1-b0e2-5adb2b6d7349\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"f8c127c2-60ef-47b1-b0e2-5adb2b6d7349\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"f8c127c2-60ef-47b1-b0e2-5adb2b6d7349\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"f8c127c2-60ef-47b1-b0e2-5adb2b6d7349\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"f8c127c2-60ef-47b1-b0e2-5adb2b6d7349\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"f8c127c2-60ef-47b1-b0e2-5adb2b6d7349\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612180,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"f8c127c2-60ef-47b1-b0e2-5adb2b6d7349\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612180,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"f8c127c2-60ef-47b1-b0e2-5adb2b6d7349\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612180} {\"correlation_id\":\"f8c127c2-60ef-47b1-b0e2-5adb2b6d7349\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612180,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"f8c127c2-60ef-47b1-b0e2-5adb2b6d7349\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612180,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"f8c127c2-60ef-47b1-b0e2-5adb2b6d7349\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611455,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"0869934c-f4d0-46a1-8387-f2393c5bce93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611455} {\"correlation_id\":\"0869934c-f4d0-46a1-8387-f2393c5bce93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611455,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"0869934c-f4d0-46a1-8387-f2393c5bce93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611455,\"participants\":[{\"id\":997961,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997962,\"user_id\":1460,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"0869934c-f4d0-46a1-8387-f2393c5bce93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"0869934c-f4d0-46a1-8387-f2393c5bce93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"0869934c-f4d0-46a1-8387-f2393c5bce93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"0869934c-f4d0-46a1-8387-f2393c5bce93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"0869934c-f4d0-46a1-8387-f2393c5bce93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"0869934c-f4d0-46a1-8387-f2393c5bce93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"support@staging.jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/support%40staging.jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"correlation_id\":\"0869934c-f4d0-46a1-8387-f2393c5bce93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"0869934c-f4d0-46a1-8387-f2393c5bce93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"0869934c-f4d0-46a1-8387-f2393c5bce93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611451,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"4e3d1181-634e-4ea2-8ac6-7da2a722c455\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611451} {\"correlation_id\":\"4e3d1181-634e-4ea2-8ac6-7da2a722c455\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611451,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"4e3d1181-634e-4ea2-8ac6-7da2a722c455\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611451,\"participants\":[{\"id\":997955,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997956,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"4e3d1181-634e-4ea2-8ac6-7da2a722c455\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4e3d1181-634e-4ea2-8ac6-7da2a722c455\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4e3d1181-634e-4ea2-8ac6-7da2a722c455\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"4e3d1181-634e-4ea2-8ac6-7da2a722c455\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"4e3d1181-634e-4ea2-8ac6-7da2a722c455\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"4e3d1181-634e-4ea2-8ac6-7da2a722c455\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"support@staging.jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/support%40staging.jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"correlation_id\":\"4e3d1181-634e-4ea2-8ac6-7da2a722c455\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"4e3d1181-634e-4ea2-8ac6-7da2a722c455\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"4e3d1181-634e-4ea2-8ac6-7da2a722c455\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611087,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"bd88fcdb-25fc-4e20-bec3-36897d7c6d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611087} {\"correlation_id\":\"bd88fcdb-25fc-4e20-bec3-36897d7c6d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611087,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"bd88fcdb-25fc-4e20-bec3-36897d7c6d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611087,\"participants\":[{\"id\":997368,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997369,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"bd88fcdb-25fc-4e20-bec3-36897d7c6d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"bd88fcdb-25fc-4e20-bec3-36897d7c6d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"bd88fcdb-25fc-4e20-bec3-36897d7c6d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"bd88fcdb-25fc-4e20-bec3-36897d7c6d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"bd88fcdb-25fc-4e20-bec3-36897d7c6d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"bd88fcdb-25fc-4e20-bec3-36897d7c6d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"bd88fcdb-25fc-4e20-bec3-36897d7c6d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":10} {\"correlation_id\":\"bd88fcdb-25fc-4e20-bec3-36897d7c6d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611076,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"c1d5bb08-3fac-4938-926a-3e672915d6c3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611076} {\"correlation_id\":\"c1d5bb08-3fac-4938-926a-3e672915d6c3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611076,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"c1d5bb08-3fac-4938-926a-3e672915d6c3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611076,\"participants\":[{\"id\":997346,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997347,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"c1d5bb08-3fac-4938-926a-3e672915d6c3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"c1d5bb08-3fac-4938-926a-3e672915d6c3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"c1d5bb08-3fac-4938-926a-3e672915d6c3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"c1d5bb08-3fac-4938-926a-3e672915d6c3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"c1d5bb08-3fac-4938-926a-3e672915d6c3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"c1d5bb08-3fac-4938-926a-3e672915d6c3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"c1d5bb08-3fac-4938-926a-3e672915d6c3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":10} {\"correlation_id\":\"c1d5bb08-3fac-4938-926a-3e672915d6c3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610935,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"c1161db6-2192-487f-94d9-fb763ee00ea9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610935} {\"correlation_id\":\"c1161db6-2192-487f-94d9-fb763ee00ea9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610935,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"c1161db6-2192-487f-94d9-fb763ee00ea9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610935,\"participants\":[{\"id\":997141,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997142,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"c1161db6-2192-487f-94d9-fb763ee00ea9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"c1161db6-2192-487f-94d9-fb763ee00ea9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"c1161db6-2192-487f-94d9-fb763ee00ea9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"c1161db6-2192-487f-94d9-fb763ee00ea9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"c1161db6-2192-487f-94d9-fb763ee00ea9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"c1161db6-2192-487f-94d9-fb763ee00ea9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"c1161db6-2192-487f-94d9-fb763ee00ea9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"c1161db6-2192-487f-94d9-fb763ee00ea9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610915,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"bd974d1f-98c3-43ec-a0ee-c373b13e5a55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610915} {\"correlation_id\":\"bd974d1f-98c3-43ec-a0ee-c373b13e5a55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610915,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"bd974d1f-98c3-43ec-a0ee-c373b13e5a55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610915,\"participants\":[{\"id\":997104,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997105,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"bd974d1f-98c3-43ec-a0ee-c373b13e5a55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"bd974d1f-98c3-43ec-a0ee-c373b13e5a55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"bd974d1f-98c3-43ec-a0ee-c373b13e5a55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"bd974d1f-98c3-43ec-a0ee-c373b13e5a55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"bd974d1f-98c3-43ec-a0ee-c373b13e5a55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"bd974d1f-98c3-43ec-a0ee-c373b13e5a55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"bd974d1f-98c3-43ec-a0ee-c373b13e5a55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":13} {\"correlation_id\":\"bd974d1f-98c3-43ec-a0ee-c373b13e5a55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610900,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"6b6b45e9-7387-4b73-a6c1-1302a6e959cc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610900} {\"correlation_id\":\"6b6b45e9-7387-4b73-a6c1-1302a6e959cc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610900,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"6b6b45e9-7387-4b73-a6c1-1302a6e959cc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610900,\"participants\":[{\"id\":997081,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997082,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"6b6b45e9-7387-4b73-a6c1-1302a6e959cc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"6b6b45e9-7387-4b73-a6c1-1302a6e959cc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"6b6b45e9-7387-4b73-a6c1-1302a6e959cc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6b6b45e9-7387-4b73-a6c1-1302a6e959cc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"6b6b45e9-7387-4b73-a6c1-1302a6e959cc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"6b6b45e9-7387-4b73-a6c1-1302a6e959cc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"6b6b45e9-7387-4b73-a6c1-1302a6e959cc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":10} {\"correlation_id\":\"6b6b45e9-7387-4b73-a6c1-1302a6e959cc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610885,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"3d3fbb4c-6268-4e40-bf22-931be4baeb1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610885} {\"correlation_id\":\"3d3fbb4c-6268-4e40-bf22-931be4baeb1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610885,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"3d3fbb4c-6268-4e40-bf22-931be4baeb1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610885,\"participants\":[{\"id\":997051,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997052,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"3d3fbb4c-6268-4e40-bf22-931be4baeb1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"3d3fbb4c-6268-4e40-bf22-931be4baeb1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"3d3fbb4c-6268-4e40-bf22-931be4baeb1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"3d3fbb4c-6268-4e40-bf22-931be4baeb1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"3d3fbb4c-6268-4e40-bf22-931be4baeb1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"3d3fbb4c-6268-4e40-bf22-931be4baeb1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"3d3fbb4c-6268-4e40-bf22-931be4baeb1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"3d3fbb4c-6268-4e40-bf22-931be4baeb1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610878,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"75bdd542-1e62-4704-861a-810a631074bf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610878} {\"correlation_id\":\"75bdd542-1e62-4704-861a-810a631074bf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610878,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"75bdd542-1e62-4704-861a-810a631074bf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610878,\"participants\":[{\"id\":997035,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997036,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"75bdd542-1e62-4704-861a-810a631074bf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"75bdd542-1e62-4704-861a-810a631074bf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"75bdd542-1e62-4704-861a-810a631074bf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"75bdd542-1e62-4704-861a-810a631074bf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"75bdd542-1e62-4704-861a-810a631074bf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"75bdd542-1e62-4704-861a-810a631074bf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"75bdd542-1e62-4704-861a-810a631074bf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"75bdd542-1e62-4704-861a-810a631074bf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610874,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"923e5701-fa97-4252-a235-5cfe1a50c951\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610874} {\"correlation_id\":\"923e5701-fa97-4252-a235-5cfe1a50c951\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610874,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"923e5701-fa97-4252-a235-5cfe1a50c951\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610874,\"participants\":[{\"id\":997025,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997026,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"923e5701-fa97-4252-a235-5cfe1a50c951\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"923e5701-fa97-4252-a235-5cfe1a50c951\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"923e5701-fa97-4252-a235-5cfe1a50c951\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"923e5701-fa97-4252-a235-5cfe1a50c951\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"923e5701-fa97-4252-a235-5cfe1a50c951\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"923e5701-fa97-4252-a235-5cfe1a50c951\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"923e5701-fa97-4252-a235-5cfe1a50c951\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":15} {\"correlation_id\":\"923e5701-fa97-4252-a235-5cfe1a50c951\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:30] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610867,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"afecdc02-a4b8-431a-baee-e5f104160539\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:30] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610867} {\"correlation_id\":\"afecdc02-a4b8-431a-baee-e5f104160539\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:30] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610867,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"afecdc02-a4b8-431a-baee-e5f104160539\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:30] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610867,\"participants\":[{\"id\":997011,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997012,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"afecdc02-a4b8-431a-baee-e5f104160539\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:30] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"afecdc02-a4b8-431a-baee-e5f104160539\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:30] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"afecdc02-a4b8-431a-baee-e5f104160539\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:30] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"afecdc02-a4b8-431a-baee-e5f104160539\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:30] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"afecdc02-a4b8-431a-baee-e5f104160539\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"afecdc02-a4b8-431a-baee-e5f104160539\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"afecdc02-a4b8-431a-baee-e5f104160539\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"afecdc02-a4b8-431a-baee-e5f104160539\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610764,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"30a67f60-f844-4758-bc2c-79a6b1ec958a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610764} {\"correlation_id\":\"30a67f60-f844-4758-bc2c-79a6b1ec958a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610764,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"30a67f60-f844-4758-bc2c-79a6b1ec958a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610764,\"participants\":[{\"id\":996951,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996952,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"30a67f60-f844-4758-bc2c-79a6b1ec958a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"30a67f60-f844-4758-bc2c-79a6b1ec958a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"30a67f60-f844-4758-bc2c-79a6b1ec958a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"30a67f60-f844-4758-bc2c-79a6b1ec958a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"30a67f60-f844-4758-bc2c-79a6b1ec958a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"30a67f60-f844-4758-bc2c-79a6b1ec958a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"30a67f60-f844-4758-bc2c-79a6b1ec958a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":10} {\"correlation_id\":\"30a67f60-f844-4758-bc2c-79a6b1ec958a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610617,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"2989f086-0b73-4b12-b24c-8665376dcf18\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610617} {\"correlation_id\":\"2989f086-0b73-4b12-b24c-8665376dcf18\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610617,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"2989f086-0b73-4b12-b24c-8665376dcf18\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610617,\"participants\":[{\"id\":996641,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996642,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"2989f086-0b73-4b12-b24c-8665376dcf18\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"2989f086-0b73-4b12-b24c-8665376dcf18\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"2989f086-0b73-4b12-b24c-8665376dcf18\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"2989f086-0b73-4b12-b24c-8665376dcf18\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"2989f086-0b73-4b12-b24c-8665376dcf18\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"2989f086-0b73-4b12-b24c-8665376dcf18\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"2989f086-0b73-4b12-b24c-8665376dcf18\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"2989f086-0b73-4b12-b24c-8665376dcf18\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [ EsUpdateProcessManager ] Finished updating entities in ES {\"worker\":\"\",\"peak_memory\":\"99.73 MB\",\"elapsed_seconds\":0.9,\"update_target\":\"activities\",\"should_iterate_again\":false} {\"correlation_id\":\"4ad05333-9afb-492e-9f0f-b2909ac45b32\",\"trace_id\":\"3d8feb24-b173-4158-b0a4-4cf33af85066\"}\n[2026-05-11 10:17:31] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610539,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"0c19e519-0adf-4903-a45d-44559f23151f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610539} {\"correlation_id\":\"0c19e519-0adf-4903-a45d-44559f23151f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610539,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"0c19e519-0adf-4903-a45d-44559f23151f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610539,\"participants\":[{\"id\":996485,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996486,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"0c19e519-0adf-4903-a45d-44559f23151f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"0c19e519-0adf-4903-a45d-44559f23151f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"0c19e519-0adf-4903-a45d-44559f23151f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"0c19e519-0adf-4903-a45d-44559f23151f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"0c19e519-0adf-4903-a45d-44559f23151f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"0c19e519-0adf-4903-a45d-44559f23151f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"0c19e519-0adf-4903-a45d-44559f23151f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":10} {\"correlation_id\":\"0c19e519-0adf-4903-a45d-44559f23151f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610528,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"fc1002b7-ac5b-4080-b6fa-497070177a88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610528} {\"correlation_id\":\"fc1002b7-ac5b-4080-b6fa-497070177a88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610528,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"fc1002b7-ac5b-4080-b6fa-497070177a88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610528,\"participants\":[{\"id\":996463,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996464,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"fc1002b7-ac5b-4080-b6fa-497070177a88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"fc1002b7-ac5b-4080-b6fa-497070177a88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"fc1002b7-ac5b-4080-b6fa-497070177a88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"fc1002b7-ac5b-4080-b6fa-497070177a88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"fc1002b7-ac5b-4080-b6fa-497070177a88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"fc1002b7-ac5b-4080-b6fa-497070177a88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"fc1002b7-ac5b-4080-b6fa-497070177a88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"fc1002b7-ac5b-4080-b6fa-497070177a88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610506,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"738402b4-5306-4346-9286-7b1fb94db69f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610506} {\"correlation_id\":\"738402b4-5306-4346-9286-7b1fb94db69f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610506,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"738402b4-5306-4346-9286-7b1fb94db69f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610506,\"participants\":[{\"id\":996419,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996420,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"738402b4-5306-4346-9286-7b1fb94db69f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"738402b4-5306-4346-9286-7b1fb94db69f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"738402b4-5306-4346-9286-7b1fb94db69f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"738402b4-5306-4346-9286-7b1fb94db69f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"738402b4-5306-4346-9286-7b1fb94db69f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"738402b4-5306-4346-9286-7b1fb94db69f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"738402b4-5306-4346-9286-7b1fb94db69f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":13} {\"correlation_id\":\"738402b4-5306-4346-9286-7b1fb94db69f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610497,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"2356bf77-077c-400e-ac58-cebd0719ff80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610497} {\"correlation_id\":\"2356bf77-077c-400e-ac58-cebd0719ff80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610497,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"2356bf77-077c-400e-ac58-cebd0719ff80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610497,\"participants\":[{\"id\":996401,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996402,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"2356bf77-077c-400e-ac58-cebd0719ff80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"2356bf77-077c-400e-ac58-cebd0719ff80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"2356bf77-077c-400e-ac58-cebd0719ff80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"2356bf77-077c-400e-ac58-cebd0719ff80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"2356bf77-077c-400e-ac58-cebd0719ff80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"2356bf77-077c-400e-ac58-cebd0719ff80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"2356bf77-077c-400e-ac58-cebd0719ff80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.WARNING: [Hubspot] No retry-after header or policy name found, using default {\"exception_class\":\"SevenShores\\\\Hubspot\\\\Exceptions\\\\BadRequest\"} {\"correlation_id\":\"2356bf77-077c-400e-ac58-cebd0719ff80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.WARNING: [Hubspot] Received 429 from API {\"team_id\":2,\"config_id\":2,\"retry_after\":10,\"policy\":null,\"reason\":\"Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response:\n{\\\"status\\\":\\\"error\\\",\\\"message\\\":\\\"You have reached your secondly limit.\\\",\\\"errorType\\\":\\\"RATE_LIMIT\\\",\\\"correlationId\\\":\\\"019e168a-c (truncated...)\n\"} {\"correlation_id\":\"2356bf77-077c-400e-ac58-cebd0719ff80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":12} {\"correlation_id\":\"2356bf77-077c-400e-ac58-cebd0719ff80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610490,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"2e2173eb-7d9e-43e9-b8e2-2c6bb1d4c684\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610490} {\"correlation_id\":\"2e2173eb-7d9e-43e9-b8e2-2c6bb1d4c684\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610490,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"2e2173eb-7d9e-43e9-b8e2-2c6bb1d4c684\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610490,\"participants\":[{\"id\":996385,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996386,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"2e2173eb-7d9e-43e9-b8e2-2c6bb1d4c684\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"2e2173eb-7d9e-43e9-b8e2-2c6bb1d4c684\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"2e2173eb-7d9e-43e9-b8e2-2c6bb1d4c684\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"2e2173eb-7d9e-43e9-b8e2-2c6bb1d4c684\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"2e2173eb-7d9e-43e9-b8e2-2c6bb1d4c684\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"2e2173eb-7d9e-43e9-b8e2-2c6bb1d4c684\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"2e2173eb-7d9e-43e9-b8e2-2c6bb1d4c684\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":10} {\"correlation_id\":\"2e2173eb-7d9e-43e9-b8e2-2c6bb1d4c684\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610470,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"63a0af1c-277e-446c-9a48-9757a8d34ddc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610470} {\"correlation_id\":\"63a0af1c-277e-446c-9a48-9757a8d34ddc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610470,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"63a0af1c-277e-446c-9a48-9757a8d34ddc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610470,\"participants\":[{\"id\":996369,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996370,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"63a0af1c-277e-446c-9a48-9757a8d34ddc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"63a0af1c-277e-446c-9a48-9757a8d34ddc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"63a0af1c-277e-446c-9a48-9757a8d34ddc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"63a0af1c-277e-446c-9a48-9757a8d34ddc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"63a0af1c-277e-446c-9a48-9757a8d34ddc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"63a0af1c-277e-446c-9a48-9757a8d34ddc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"63a0af1c-277e-446c-9a48-9757a8d34ddc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":15} {\"correlation_id\":\"63a0af1c-277e-446c-9a48-9757a8d34ddc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610462,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"b324376c-1fd3-497f-b0fb-004f86f50635\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610462} {\"correlation_id\":\"b324376c-1fd3-497f-b0fb-004f86f50635\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610462,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"b324376c-1fd3-497f-b0fb-004f86f50635\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610462,\"participants\":[{\"id\":996353,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996354,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"b324376c-1fd3-497f-b0fb-004f86f50635\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b324376c-1fd3-497f-b0fb-004f86f50635\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b324376c-1fd3-497f-b0fb-004f86f50635\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"b324376c-1fd3-497f-b0fb-004f86f50635\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"b324376c-1fd3-497f-b0fb-004f86f50635\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"b324376c-1fd3-497f-b0fb-004f86f50635\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"b324376c-1fd3-497f-b0fb-004f86f50635\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"b324376c-1fd3-497f-b0fb-004f86f50635\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610451,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"b2b3cc5b-60ce-4c18-bb68-76d30013357c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610451} {\"correlation_id\":\"b2b3cc5b-60ce-4c18-bb68-76d30013357c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610451,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"b2b3cc5b-60ce-4c18-bb68-76d30013357c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610451,\"participants\":[{\"id\":996340,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996341,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"b2b3cc5b-60ce-4c18-bb68-76d30013357c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b2b3cc5b-60ce-4c18-bb68-76d30013357c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b2b3cc5b-60ce-4c18-bb68-76d30013357c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"b2b3cc5b-60ce-4c18-bb68-76d30013357c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"b2b3cc5b-60ce-4c18-bb68-76d30013357c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"b2b3cc5b-60ce-4c18-bb68-76d30013357c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"b2b3cc5b-60ce-4c18-bb68-76d30013357c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"b2b3cc5b-60ce-4c18-bb68-76d30013357c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610438,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"d6026499-3681-474a-85f7-3faee13605b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610438} {\"correlation_id\":\"d6026499-3681-474a-85f7-3faee13605b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610438,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"d6026499-3681-474a-85f7-3faee13605b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610438,\"participants\":[{\"id\":996320,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996321,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"d6026499-3681-474a-85f7-3faee13605b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"d6026499-3681-474a-85f7-3faee13605b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"d6026499-3681-474a-85f7-3faee13605b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"d6026499-3681-474a-85f7-3faee13605b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"d6026499-3681-474a-85f7-3faee13605b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"d6026499-3681-474a-85f7-3faee13605b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"d6026499-3681-474a-85f7-3faee13605b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":13} {\"correlation_id\":\"d6026499-3681-474a-85f7-3faee13605b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610426,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"17b3d9a6-2eb0-49d1-8a00-c67c644885e1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610426} {\"correlation_id\":\"17b3d9a6-2eb0-49d1-8a00-c67c644885e1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610426,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"17b3d9a6-2eb0-49d1-8a00-c67c644885e1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610426,\"participants\":[{\"id\":996306,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996307,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"17b3d9a6-2eb0-49d1-8a00-c67c644885e1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"17b3d9a6-2eb0-49d1-8a00-c67c644885e1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"17b3d9a6-2eb0-49d1-8a00-c67c644885e1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"17b3d9a6-2eb0-49d1-8a00-c67c644885e1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"17b3d9a6-2eb0-49d1-8a00-c67c644885e1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"17b3d9a6-2eb0-49d1-8a00-c67c644885e1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"17b3d9a6-2eb0-49d1-8a00-c67c644885e1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":15} {\"correlation_id\":\"17b3d9a6-2eb0-49d1-8a00-c67c644885e1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610403,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"112a2c70-a5f2-4500-9726-7f560d683236\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610403} {\"correlation_id\":\"112a2c70-a5f2-4500-9726-7f560d683236\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610403,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"112a2c70-a5f2-4500-9726-7f560d683236\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610403,\"participants\":[{\"id\":996282,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996283,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"112a2c70-a5f2-4500-9726-7f560d683236\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"112a2c70-a5f2-4500-9726-7f560d683236\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"112a2c70-a5f2-4500-9726-7f560d683236\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"112a2c70-a5f2-4500-9726-7f560d683236\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"112a2c70-a5f2-4500-9726-7f560d683236\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"112a2c70-a5f2-4500-9726-7f560d683236\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"112a2c70-a5f2-4500-9726-7f560d683236\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"112a2c70-a5f2-4500-9726-7f560d683236\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610400,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":350,\"stage_id\":34}} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610400} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610400,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610400,\"participants\":[{\"id\":996275,\"user_id\":1460,\"contact_id\":null,\"lead_id\":null},{\"id\":996276,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":996277,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null}]} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610400,\"team_id\":2,\"email\":\"aneliya.angelova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610400,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: ProspectCache - Searching DB for opportunity by owner {\"account_id\":244,\"contact_id\":4487,\"owner_id\":1460} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: ProspectCache - Fallback DB opportunity search {\"account_id\":244,\"contact_id\":4487} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: ProspectCache - Opportunity DB search results {\"account_id\":244,\"contact_id\":4487,\"opportunity_id\":350} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610400,\"participants_processed\":3,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610400} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610400,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610400,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":350,\"stage_id\":34} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614381,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6868b438-d843-4331-9862-f802e4cc4ff2\"}\n[2026-05-11 10:17:34] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614381} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6868b438-d843-4331-9862-f802e4cc4ff2\"}\n[2026-05-11 10:17:34] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614381,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6868b438-d843-4331-9862-f802e4cc4ff2\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614381,\"participants\":[{\"id\":1002630,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002631,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6868b438-d843-4331-9862-f802e4cc4ff2\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6868b438-d843-4331-9862-f802e4cc4ff2\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6868b438-d843-4331-9862-f802e4cc4ff2\"}\n[2026-05-11 10:17:34] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6868b438-d843-4331-9862-f802e4cc4ff2\"}\n[2026-05-11 10:17:34] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6868b438-d843-4331-9862-f802e4cc4ff2\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6868b438-d843-4331-9862-f802e4cc4ff2\"}\n[2026-05-11 10:17:34] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"nikolay.nikolov@jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/nikolay.nikolov%40jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6868b438-d843-4331-9862-f802e4cc4ff2\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6868b438-d843-4331-9862-f802e4cc4ff2\"}\n[2026-05-11 10:17:34] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":10} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6868b438-d843-4331-9862-f802e4cc4ff2\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614382,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f600c314-da4f-48ea-885b-f3b0db553881\"}\n[2026-05-11 10:17:34] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614382} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f600c314-da4f-48ea-885b-f3b0db553881\"}\n[2026-05-11 10:17:34] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614382,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f600c314-da4f-48ea-885b-f3b0db553881\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614382,\"participants\":[{\"id\":1002632,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002633,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f600c314-da4f-48ea-885b-f3b0db553881\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f600c314-da4f-48ea-885b-f3b0db553881\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f600c314-da4f-48ea-885b-f3b0db553881\"}\n[2026-05-11 10:17:34] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f600c314-da4f-48ea-885b-f3b0db553881\"}\n[2026-05-11 10:17:34] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f600c314-da4f-48ea-885b-f3b0db553881\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f600c314-da4f-48ea-885b-f3b0db553881\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f600c314-da4f-48ea-885b-f3b0db553881\"}\n[2026-05-11 10:17:34] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":10} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f600c314-da4f-48ea-885b-f3b0db553881\"}\n[2026-05-11 10:17:34] local.NOTICE: Monitoring start {\"correlation_id\":\"2a3353ba-9883-42be-b596-9e38bd5fc160\",\"trace_id\":\"fc84fbbd-f6ab-40f6-8fdc-f023fbe3b46e\"}\n[2026-05-11 10:17:34] local.NOTICE: Monitoring end {\"correlation_id\":\"2a3353ba-9883-42be-b596-9e38bd5fc160\",\"trace_id\":\"fc84fbbd-f6ab-40f6-8fdc-f023fbe3b46e\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612819,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ac88094e-4a12-4e5c-87dd-c7701d7a8719\"}\n[2026-05-11 10:17:34] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612819} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ac88094e-4a12-4e5c-87dd-c7701d7a8719\"}\n[2026-05-11 10:17:34] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612819,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ac88094e-4a12-4e5c-87dd-c7701d7a8719\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612819,\"participants\":[{\"id\":1000073,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1000074,\"user_id\":261,\"contact_id\":null,\"lead_id\":null},{\"id\":1000075,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ac88094e-4a12-4e5c-87dd-c7701d7a8719\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ac88094e-4a12-4e5c-87dd-c7701d7a8719\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ac88094e-4a12-4e5c-87dd-c7701d7a8719\"}\n[2026-05-11 10:17:34] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ac88094e-4a12-4e5c-87dd-c7701d7a8719\"}\n[2026-05-11 10:17:34] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ac88094e-4a12-4e5c-87dd-c7701d7a8719\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ac88094e-4a12-4e5c-87dd-c7701d7a8719\"}\n[2026-05-11 10:17:34] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612819,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ac88094e-4a12-4e5c-87dd-c7701d7a8719\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ac88094e-4a12-4e5c-87dd-c7701d7a8719\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ac88094e-4a12-4e5c-87dd-c7701d7a8719\"}\n[2026-05-11 10:17:34] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":11} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ac88094e-4a12-4e5c-87dd-c7701d7a8719\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":615092,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"5b7869a5-e05c-417f-819f-12774e20bb56\"}\n[2026-05-11 10:17:34] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":615092} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"5b7869a5-e05c-417f-819f-12774e20bb56\"}\n[2026-05-11 10:17:34] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":615092,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"5b7869a5-e05c-417f-819f-12774e20bb56\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":615092,\"participants\":[{\"id\":1004102,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1004103,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"5b7869a5-e05c-417f-819f-12774e20bb56\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"5b7869a5-e05c-417f-819f-12774e20bb56\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"5b7869a5-e05c-417f-819f-12774e20bb56\"}\n[2026-05-11 10:17:34] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"5b7869a5-e05c-417f-819f-12774e20bb56\"}\n[2026-05-11 10:17:34] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"5b7869a5-e05c-417f-819f-12774e20bb56\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"5b7869a5-e05c-417f-819f-12774e20bb56\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"5b7869a5-e05c-417f-819f-12774e20bb56\"}\n[2026-05-11 10:17:34] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":14} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"5b7869a5-e05c-417f-819f-12774e20bb56\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614436,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72bb1bed-9270-436f-977c-a73c970415a3\"}\n[2026-05-11 10:17:34] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614436} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72bb1bed-9270-436f-977c-a73c970415a3\"}\n[2026-05-11 10:17:34] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614436,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72bb1bed-9270-436f-977c-a73c970415a3\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614436,\"participants\":[{\"id\":1002751,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002752,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72bb1bed-9270-436f-977c-a73c970415a3\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72bb1bed-9270-436f-977c-a73c970415a3\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72bb1bed-9270-436f-977c-a73c970415a3\"}\n[2026-05-11 10:17:34] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72bb1bed-9270-436f-977c-a73c970415a3\"}\n[2026-05-11 10:17:34] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72bb1bed-9270-436f-977c-a73c970415a3\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72bb1bed-9270-436f-977c-a73c970415a3\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72bb1bed-9270-436f-977c-a73c970415a3\"}\n[2026-05-11 10:17:34] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":13} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72bb1bed-9270-436f-977c-a73c970415a3\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614378,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":6167,\"account_id\":null,\"opportunity_id\":null,\"stage_id\":null}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ef02c9ff-d0fc-47cb-aeb0-e8ba837de699\"}\n[2026-05-11 10:17:34] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614378} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ef02c9ff-d0fc-47cb-aeb0-e8ba837de699\"}\n[2026-05-11 10:17:34] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614378,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ef02c9ff-d0fc-47cb-aeb0-e8ba837de699\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614378,\"participants\":[{\"id\":1002623,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002624,\"user_id\":null,\"contact_id\":6167,\"lead_id\":null},{\"id\":1002625,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ef02c9ff-d0fc-47cb-aeb0-e8ba837de699\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ef02c9ff-d0fc-47cb-aeb0-e8ba837de699\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ef02c9ff-d0fc-47cb-aeb0-e8ba837de699\"}\n[2026-05-11 10:17:34] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ef02c9ff-d0fc-47cb-aeb0-e8ba837de699\"}\n[2026-05-11 10:17:34] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ef02c9ff-d0fc-47cb-aeb0-e8ba837de699\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ef02c9ff-d0fc-47cb-aeb0-e8ba837de699\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ef02c9ff-d0fc-47cb-aeb0-e8ba837de699\"}\n[2026-05-11 10:17:34] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":12} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ef02c9ff-d0fc-47cb-aeb0-e8ba837de699\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612847,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e1608ca2-4101-4e24-8c9f-29ba81ce925f\"}\n[2026-05-11 10:17:34] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612847} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e1608ca2-4101-4e24-8c9f-29ba81ce925f\"}\n[2026-05-11 10:17:34] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612847,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e1608ca2-4101-4e24-8c9f-29ba81ce925f\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612847,\"participants\":[{\"id\":1000130,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1000131,\"user_id\":261,\"contact_id\":null,\"lead_id\":null},{\"id\":1000151,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e1608ca2-4101-4e24-8c9f-29ba81ce925f\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e1608ca2-4101-4e24-8c9f-29ba81ce925f\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e1608ca2-4101-4e24-8c9f-29ba81ce925f\"}\n[2026-05-11 10:17:34] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e1608ca2-4101-4e24-8c9f-29ba81ce925f\"}\n[2026-05-11 10:17:34] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e1608ca2-4101-4e24-8c9f-29ba81ce925f\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e1608ca2-4101-4e24-8c9f-29ba81ce925f\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e1608ca2-4101-4e24-8c9f-29ba81ce925f\"}\n[2026-05-11 10:17:34] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":11} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e1608ca2-4101-4e24-8c9f-29ba81ce925f\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612562,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"40f1c570-c73a-4bea-99d1-0b405485c1eb\"}\n[2026-05-11 10:17:34] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612562} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"40f1c570-c73a-4bea-99d1-0b405485c1eb\"}\n[2026-05-11 10:17:34] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612562,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"40f1c570-c73a-4bea-99d1-0b405485c1eb\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612562,\"participants\":[{\"id\":999782,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999783,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"40f1c570-c73a-4bea-99d1-0b405485c1eb\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"40f1c570-c73a-4bea-99d1-0b405485c1eb\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"40f1c570-c73a-4bea-99d1-0b405485c1eb\"}\n[2026-05-11 10:17:34] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"40f1c570-c73a-4bea-99d1-0b405485c1eb\"}\n[2026-05-11 10:17:34] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"40f1c570-c73a-4bea-99d1-0b405485c1eb\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"40f1c570-c73a-4bea-99d1-0b405485c1eb\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"40f1c570-c73a-4bea-99d1-0b405485c1eb\"}\n[2026-05-11 10:17:34] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":14} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"40f1c570-c73a-4bea-99d1-0b405485c1eb\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612560,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6f43c701-78e8-4a90-bc73-feecc83e035c\"}\n[2026-05-11 10:17:34] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612560} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6f43c701-78e8-4a90-bc73-feecc83e035c\"}\n[2026-05-11 10:17:34] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612560,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6f43c701-78e8-4a90-bc73-feecc83e035c\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612560,\"participants\":[{\"id\":999778,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999779,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6f43c701-78e8-4a90-bc73-feecc83e035c\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6f43c701-78e8-4a90-bc73-feecc83e035c\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6f43c701-78e8-4a90-bc73-feecc83e035c\"}\n[2026-05-11 10:17:34] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6f43c701-78e8-4a90-bc73-feecc83e035c\"}\n[2026-05-11 10:17:34] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6f43c701-78e8-4a90-bc73-feecc83e035c\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6f43c701-78e8-4a90-bc73-feecc83e035c\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6f43c701-78e8-4a90-bc73-feecc83e035c\"}\n[2026-05-11 10:17:34] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":10} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6f43c701-78e8-4a90-bc73-feecc83e035c\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612561,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"714584dc-ec4b-479a-aecd-db6c109f4a6d\"}\n[2026-05-11 10:17:34] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612561} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"714584dc-ec4b-479a-aecd-db6c109f4a6d\"}\n[2026-05-11 10:17:34] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612561,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"714584dc-ec4b-479a-aecd-db6c109f4a6d\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612561,\"participants\":[{\"id\":999780,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999781,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"714584dc-ec4b-479a-aecd-db6c109f4a6d\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"714584dc-ec4b-479a-aecd-db6c109f4a6d\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"714584dc-ec4b-479a-aecd-db6c109f4a6d\"}\n[2026-05-11 10:17:34] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"714584dc-ec4b-479a-aecd-db6c109f4a6d\"}\n[2026-05-11 10:17:34] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"714584dc-ec4b-479a-aecd-db6c109f4a6d\"}\n[2026-05-11 10:17:34] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612561,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"714584dc-ec4b-479a-aecd-db6c109f4a6d\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"447700174614.447782589921.OeREojLVnk@txt.staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"714584dc-ec4b-479a-aecd-db6c109f4a6d\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"447700174614.447782589921.OeREojLVnk@txt.staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"714584dc-ec4b-479a-aecd-db6c109f4a6d\"}\n[2026-05-11 10:17:34] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":12} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"714584dc-ec4b-479a-aecd-db6c109f4a6d\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612340,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f7f53665-81f1-4b01-86eb-56ad96f088db\"}\n[2026-05-11 10:17:34] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612340} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f7f53665-81f1-4b01-86eb-56ad96f088db\"}\n[2026-05-11 10:17:34] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612340,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f7f53665-81f1-4b01-86eb-56ad96f088db\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612340,\"participants\":[{\"id\":999516,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999517,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999518,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999519,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f7f53665-81f1-4b01-86eb-56ad96f088db\"}\n[2026-05-11 10:17:35] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f7f53665-81f1-4b01-86eb-56ad96f088db\"}\n[2026-05-11 10:17:35] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f7f53665-81f1-4b01-86eb-56ad96f088db\"}\n[2026-05-11 10:17:35] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f7f53665-81f1-4b01-86eb-56ad96f088db\"}\n[2026-05-11 10:17:35] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f7f53665-81f1-4b01-86eb-56ad96f088db\"}\n[2026-05-11 10:17:35] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f7f53665-81f1-4b01-86eb-56ad96f088db\"}\n[2026-05-11 10:17:35] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612340,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f7f53665-81f1-4b01-86eb-56ad96f088db\"}\n[2026-05-11 10:17:35] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":14} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f7f53665-81f1-4b01-86eb-56ad96f088db\"}\n[2026-05-11 10:17:35] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612360,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7356be9b-68c6-4c39-9fbe-d16bafce4614\"}\n[2026-05-11 10:17:35] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612360} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7356be9b-68c6-4c39-9fbe-d16bafce4614\"}\n[2026-05-11 10:17:35] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612360,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7356be9b-68c6-4c39-9fbe-d16bafce4614\"}\n[2026-05-11 10:17:35] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612360,\"participants\":[{\"id\":999552,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999553,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999565,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7356be9b-68c6-4c39-9fbe-d16bafce4614\"}\n[2026-05-11 10:17:35] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7356be9b-68c6-4c39-9fbe-d16bafce4614\"}\n[2026-05-11 10:17:35] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7356be9b-68c6-4c39-9fbe-d16bafce4614\"}\n[2026-05-11 10:17:35] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7356be9b-68c6-4c39-9fbe-d16bafce4614\"}\n[2026-05-11 10:17:35] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7356be9b-68c6-4c39-9fbe-d16bafce4614\"}\n[2026-05-11 10:17:35] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7356be9b-68c6-4c39-9fbe-d16bafce4614\"}\n[2026-05-11 10:17:35] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612360,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7356be9b-68c6-4c39-9fbe-d16bafce4614\"}\n[2026-05-11 10:17:35] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":15} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7356be9b-68c6-4c39-9fbe-d16bafce4614\"}\n[2026-05-11 10:17:35] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612339,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb97cad3-6d10-4315-a771-a5c3a8aeeb31\"}\n[2026-05-11 10:17:35] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612339} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb97cad3-6d10-4315-a771-a5c3a8aeeb31\"}\n[2026-05-11 10:17:35] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612339,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb97cad3-6d10-4315-a771-a5c3a8aeeb31\"}\n[2026-05-11 10:17:35] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612339,\"participants\":[{\"id\":999514,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999515,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999540,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb97cad3-6d10-4315-a771-a5c3a8aeeb31\"}\n[2026-05-11 10:17:35] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb97cad3-6d10-4315-a771-a5c3a8aeeb31\"}\n[2026-05-11 10:17:35] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb97cad3-6d10-4315-a771-a5c3a8aeeb31\"}\n[2026-05-11 10:17:35] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb97cad3-6d10-4315-a771-a5c3a8aeeb31\"}\n[2026-05-11 10:17:35] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb97cad3-6d10-4315-a771-a5c3a8aeeb31\"}\n[2026-05-11 10:17:35] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb97cad3-6d10-4315-a771-a5c3a8aeeb31\"}\n[2026-05-11 10:17:35] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612339,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb97cad3-6d10-4315-a771-a5c3a8aeeb31\"}\n[2026-05-11 10:17:35] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":15} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb97cad3-6d10-4315-a771-a5c3a8aeeb31\"}\n[2026-05-11 10:17:36] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"b6a9ae37-beff-496a-820a-bcf0512308f2\",\"trace_id\":\"be38fb3e-0cfa-4c02-a66a-cc0cf8d3d54a\"}\n[2026-05-11 10:17:36] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"b6a9ae37-beff-496a-820a-bcf0512308f2\",\"trace_id\":\"be38fb3e-0cfa-4c02-a66a-cc0cf8d3d54a\"}\n[2026-05-11 10:17:37] local.INFO: [ EsUpdateProcessManager ] Finished updating entities in ES {\"worker\":\"\",\"peak_memory\":\"99.73 MB\",\"elapsed_seconds\":0.49,\"update_target\":\"activities\",\"should_iterate_again\":false} {\"correlation_id\":\"4ad05333-9afb-492e-9f0f-b2909ac45b32\",\"trace_id\":\"3d8feb24-b173-4158-b0a4-4cf33af85066\"}\n[2026-05-11 10:17:37] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611451,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73d4c333-df67-43c5-a413-4c675a3ebc5e\"}\n[2026-05-11 10:17:37] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611451} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73d4c333-df67-43c5-a413-4c675a3ebc5e\"}\n[2026-05-11 10:17:37] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611451,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73d4c333-df67-43c5-a413-4c675a3ebc5e\"}\n[2026-05-11 10:17:37] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611451,\"participants\":[{\"id\":997955,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997956,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73d4c333-df67-43c5-a413-4c675a3ebc5e\"}\n[2026-05-11 10:17:37] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73d4c333-df67-43c5-a413-4c675a3ebc5e\"}\n[2026-05-11 10:17:37] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73d4c333-df67-43c5-a413-4c675a3ebc5e\"}\n[2026-05-11 10:17:37] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73d4c333-df67-43c5-a413-4c675a3ebc5e\"}\n[2026-05-11 10:17:37] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73d4c333-df67-43c5-a413-4c675a3ebc5e\"}\n[2026-05-11 10:17:37] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73d4c333-df67-43c5-a413-4c675a3ebc5e\"}\n[2026-05-11 10:17:37] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73d4c333-df67-43c5-a413-4c675a3ebc5e\"}\n[2026-05-11 10:17:37] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":12} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73d4c333-df67-43c5-a413-4c675a3ebc5e\"}\n[2026-05-11 10:17:37] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611087,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0c0e087e-66cf-4404-b647-530f77b3e652\"}\n[2026-05-11 10:17:37] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611087} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0c0e087e-66cf-4404-b647-530f77b3e652\"}\n[2026-05-11 10:17:37] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611087,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0c0e087e-66cf-4404-b647-530f77b3e652\"}\n[2026-05-11 10:17:37] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611087,\"participants\":[{\"id\":997368,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997369,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0c0e087e-66cf-4404-b647-530f77b3e652\"}\n[2026-05-11 10:17:37] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0c0e087e-66cf-4404-b647-530f77b3e652\"}\n[2026-05-11 10:17:37] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0c0e087e-66cf-4404-b647-530f77b3e652\"}\n[2026-05-11 10:17:37] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0c0e087e-66cf-4404-b647-530f77b3e652\"}\n[2026-05-11 10:17:37] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0c0e087e-66cf-4404-b647-530f77b3e652\"}\n[2026-05-11 10:17:37] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0c0e087e-66cf-4404-b647-530f77b3e652\"}\n[2026-05-11 10:17:37] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0c0e087e-66cf-4404-b647-530f77b3e652\"}\n[2026-05-11 10:17:37] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":14} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0c0e087e-66cf-4404-b647-530f77b3e652\"}\n[2026-05-11 10:17:37] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611076,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8ae56005-eaea-4862-83a4-4c28e0deb862\"}\n[2026-05-11 10:17:37] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611076} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8ae56005-eaea-4862-83a4-4c28e0deb862\"}\n[2026-05-11 10:17:37] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611076,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8ae56005-eaea-4862-83a4-4c28e0deb862\"}\n[2026-05-11 10:17:37] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611076,\"participants\":[{\"id\":997346,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997347,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8ae56005-eaea-4862-83a4-4c28e0deb862\"}\n[2026-05-11 10:17:37] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8ae56005-eaea-4862-83a4-4c28e0deb862\"}\n[2026-05-11 10:17:37] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8ae56005-eaea-4862-83a4-4c28e0deb862\"}\n[2026-05-11 10:17:37] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8ae56005-eaea-4862-83a4-4c28e0deb862\"}\n[2026-05-11 10:17:37] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8ae56005-eaea-4862-83a4-4c28e0deb862\"}\n[2026-05-11 10:17:37] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8ae56005-eaea-4862-83a4-4c28e0deb862\"}\n[2026-05-11 10:17:37] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8ae56005-eaea-4862-83a4-4c28e0deb862\"}\n[2026-05-11 10:17:37] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":15} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8ae56005-eaea-4862-83a4-4c28e0deb862\"}\n[2026-05-11 10:17:38] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610900,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72f691bf-4dd5-46e4-b0aa-e6d9947e244c\"}\n[2026-05-11 10:17:38] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610900} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72f691bf-4dd5-46e4-b0aa-e6d9947e244c\"}\n[2026-05-11 10:17:38] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610900,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72f691bf-4dd5-46e4-b0aa-e6d9947e244c\"}\n[2026-05-11 10:17:38] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610900,\"participants\":[{\"id\":997081,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997082,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72f691bf-4dd5-46e4-b0aa-e6d9947e244c\"}\n[2026-05-11 10:17:38] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72f691bf-4dd5-46e4-b0aa-e6d9947e244c\"}\n[2026-05-11 10:17:38] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72f691bf-4dd5-46e4-b0aa-e6d9947e244c\"}\n[2026-05-11 10:17:38] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72f691bf-4dd5-46e4-b0aa-e6d9947e244c\"}\n[2026-05-11 10:17:38] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72f691bf-4dd5-46e4-b0aa-e6d9947e244c\"}\n[2026-05-11 10:17:38] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72f691bf-4dd5-46e4-b0aa-e6d9947e244c\"}\n[2026-05-11 10:17:38] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72f691bf-4dd5-46e4-b0aa-e6d9947e244c\"}\n[2026-05-11 10:17:38] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":10} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72f691bf-4dd5-46e4-b0aa-e6d9947e244c\"}\n[2026-05-11 10:17:38] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610935,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9c039918-1cd4-4208-bd24-8e42d3efb19e\"}\n[2026-05-11 10:17:38] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610935} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9c039918-1cd4-4208-bd24-8e42d3efb19e\"}\n[2026-05-11 10:17:38] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610935,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9c039918-1cd4-4208-bd24-8e42d3efb19e\"}\n[2026-05-11 10:17:38] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610935,\"participants\":[{\"id\":997141,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997142,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9c039918-1cd4-4208-bd24-8e42d3efb19e\"}\n[2026-05-11 10:17:38] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9c039918-1cd4-4208-bd24-8e42d3efb19e\"}\n[2026-05-11 10:17:38] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9c039918-1cd4-4208-bd24-8e42d3efb19e\"}\n[2026-05-11 10:17:38] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9c039918-1cd4-4208-bd24-8e42d3efb19e\"}\n[2026-05-11 10:17:38] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9c039918-1cd4-4208-bd24-8e42d3efb19e\"}\n[2026-05-11 10:17:38] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9c039918-1cd4-4208-bd24-8e42d3efb19e\"}\n[2026-05-11 10:17:38] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9c039918-1cd4-4208-bd24-8e42d3efb19e\"}\n[2026-05-11 10:17:38] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":10} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9c039918-1cd4-4208-bd24-8e42d3efb19e\"}\n[2026-05-11 10:17:39] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"07a987cd-1db5-4796-b217-d8d2d1b6913e\",\"trace_id\":\"90eeb583-f4ef-4d3f-bf6e-2425312728c5\"}\n[2026-05-11 10:17:39] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"07a987cd-1db5-4796-b217-d8d2d1b6913e\",\"trace_id\":\"90eeb583-f4ef-4d3f-bf6e-2425312728c5\"}\n[2026-05-11 10:17:39] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"07a987cd-1db5-4796-b217-d8d2d1b6913e\",\"trace_id\":\"90eeb583-f4ef-4d3f-bf6e-2425312728c5\"}\n[2026-05-11 10:17:39] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"07a987cd-1db5-4796-b217-d8d2d1b6913e\",\"trace_id\":\"90eeb583-f4ef-4d3f-bf6e-2425312728c5\"}\n[2026-05-11 10:17:39] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612336,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"207e2c1f-73c1-428d-80a6-3c87aa383443\"}\n[2026-05-11 10:17:39] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612336} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"207e2c1f-73c1-428d-80a6-3c87aa383443\"}\n[2026-05-11 10:17:39] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612336,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"207e2c1f-73c1-428d-80a6-3c87aa383443\"}\n[2026-05-11 10:17:39] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612336,\"participants\":[{\"id\":999508,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999509,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999512,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999513,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"207e2c1f-73c1-428d-80a6-3c87aa383443\"}\n[2026-05-11 10:17:39] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"207e2c1f-73c1-428d-80a6-3c87aa383443\"}\n[2026-05-11 10:17:39] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"207e2c1f-73c1-428d-80a6-3c87aa383443\"}\n[2026-05-11 10:17:39] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"207e2c1f-73c1-428d-80a6-3c87aa383443\"}\n[2026-05-11 10:17:39] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"207e2c1f-73c1-428d-80a6-3c87aa383443\"}\n[2026-05-11 10:17:39] local.INFO: ProspectCache - Searching DB for opportunity by owner {\"account_id\":243,\"contact_id\":4491,\"owner_id\":206} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"207e2c1f-73c1-428d-80a6-3c87aa383443\"}\n[2026-05-11 10:17:39] local.INFO: ProspectCache - Fallback DB opportunity search {\"account_id\":243,\"contact_id\":4491} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"207e2c1f-73c1-428d-80a6-3c87aa383443\"}\n[2026-05-11 10:17:39] local.INFO: ProspectCache - Opportunity DB search results {\"account_id\":243,\"contact_id\":4491,\"opportunity_id\":276} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"207e2c1f-73c1-428d-80a6-3c87aa383443\"}\n[2026-05-11 10:17:39] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"207e2c1f-73c1-428d-80a6-3c87aa383443\"}\n[2026-05-11 10:17:39] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612336,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"207e2c1f-73c1-428d-80a6-3c87aa383443\"}\n[2026-05-11 10:17:39] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":10} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"207e2c1f-73c1-428d-80a6-3c87aa383443\"}\n[2026-05-11 10:17:40] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611455,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3b238a85-6f7e-44ab-8dac-2e8f132b32fe\"}\n[2026-05-11 10:17:40] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611455} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3b238a85-6f7e-44ab-8dac-2e8f132b32fe\"}\n[2026-05-11 10:17:40] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611455,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3b238a85-6f7e-44ab-8dac-2e8f132b32fe\"}\n[2026-05-11 10:17:40] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611455,\"participants\":[{\"id\":997961,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997962,\"user_id\":1460,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3b238a85-6f7e-44ab-8dac-2e8f132b32fe\"}\n[2026-05-11 10:17:40] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3b238a85-6f7e-44ab-8dac-2e8f132b32fe\"}\n[2026-05-11 10:17:40] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3b238a85-6f7e-44ab-8dac-2e8f132b32fe\"}\n[2026-05-11 10:17:40] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3b238a85-6f7e-44ab-8dac-2e8f132b32fe\"}\n[2026-05-11 10:17:40] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3b238a85-6f7e-44ab-8dac-2e8f132b32fe\"}\n[2026-05-11 10:17:40] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3b238a85-6f7e-44ab-8dac-2e8f132b32fe\"}\n[2026-05-11 10:17:40] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3b238a85-6f7e-44ab-8dac-2e8f132b32fe\"}\n[2026-05-11 10:17:40] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":12} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3b238a85-6f7e-44ab-8dac-2e8f132b32fe\"}\n[2026-05-11 10:17:40] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610878,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"233b41da-91f2-45fb-8a21-80d2cd24570d\"}\n[2026-05-11 10:17:40] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610878} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"233b41da-91f2-45fb-8a21-80d2cd24570d\"}\n[2026-05-11 10:17:40] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610878,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"233b41da-91f2-45fb-8a21-80d2cd24570d\"}\n[2026-05-11 10:17:40] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610878,\"participants\":[{\"id\":997035,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997036,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"233b41da-91f2-45fb-8a21-80d2cd24570d\"}\n[2026-05-11 10:17:40] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"233b41da-91f2-45fb-8a21-80d2cd24570d\"}\n[2026-05-11 10:17:40] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"233b41da-91f2-45fb-8a21-80d2cd24570d\"}\n[2026-05-11 10:17:40] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"233b41da-91f2-45fb-8a21-80d2cd24570d\"}\n[2026-05-11 10:17:40] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"233b41da-91f2-45fb-8a21-80d2cd24570d\"}\n[2026-05-11 10:17:40] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"233b41da-91f2-45fb-8a21-80d2cd24570d\"}\n[2026-05-11 10:17:40] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"233b41da-91f2-45fb-8a21-80d2cd24570d\"}\n[2026-05-11 10:17:40] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":13} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"233b41da-91f2-45fb-8a21-80d2cd24570d\"}\n[2026-05-11 10:17:41] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:create\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"e17eab55-f6ef-40c4-bcf7-0b2b4af23908\",\"trace_id\":\"fab32d53-3e12-42b6-b809-50dcad19899b\"}\n[2026-05-11 10:17:41] local.INFO: [EmailSchedule] STARTING batch create {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"e17eab55-f6ef-40c4-bcf7-0b2b4af23908\",\"trace_id\":\"fab32d53-3e12-42b6-b809-50dcad19899b\"}\n[2026-05-11 10:17:41] local.INFO: [EmailSchedule] FINISHED batch create {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"e17eab55-f6ef-40c4-bcf7-0b2b4af23908\",\"trace_id\":\"fab32d53-3e12-42b6-b809-50dcad19899b\"}\n[2026-05-11 10:17:41] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:create\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"e17eab55-f6ef-40c4-bcf7-0b2b4af23908\",\"trace_id\":\"fab32d53-3e12-42b6-b809-50dcad19899b\"}\n[2026-05-11 10:17:41] local.INFO: [Jiminny\\Jobs\\Mailbox\\CreateBatches] processed 2 inboxes and created 0 batches {\"userId\":null,\"batchSize\":30,\"maxBatches\":1000} {\"correlation_id\":\"f6431de6-0cbf-4083-96fc-d316ebac17ec\",\"trace_id\":\"fab32d53-3e12-42b6-b809-50dcad19899b\"}\n[2026-05-11 10:17:42] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610539,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ae1e1745-b1f8-4fa9-9d96-b0ec9934cbbd\"}\n[2026-05-11 10:17:42] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610539} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ae1e1745-b1f8-4fa9-9d96-b0ec9934cbbd\"}\n[2026-05-11 10:17:42] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610539,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ae1e1745-b1f8-4fa9-9d96-b0ec9934cbbd\"}\n[2026-05-11 10:17:42] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610539,\"participants\":[{\"id\":996485,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996486,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ae1e1745-b1f8-4fa9-9d96-b0ec9934cbbd\"}\n[2026-05-11 10:17:42] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ae1e1745-b1f8-4fa9-9d96-b0ec9934cbbd\"}\n[2026-05-11 10:17:42] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ae1e1745-b1f8-4fa9-9d96-b0ec9934cbbd\"}\n[2026-05-11 10:17:42] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ae1e1745-b1f8-4fa9-9d96-b0ec9934cbbd\"}\n[2026-05-11 10:17:42] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ae1e1745-b1f8-4fa9-9d96-b0ec9934cbbd\"}\n[2026-05-11 10:17:42] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ae1e1745-b1f8-4fa9-9d96-b0ec9934cbbd\"}\n[2026-05-11 10:17:42] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ae1e1745-b1f8-4fa9-9d96-b0ec9934cbbd\"}\n[2026-05-11 10:17:42] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":11} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ae1e1745-b1f8-4fa9-9d96-b0ec9934cbbd\"}\n[2026-05-11 10:17:42] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610915,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f131d63b-7da9-4a0c-b9d5-4a2d2ae772f1\"}\n[2026-05-11 10:17:42] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610915} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f131d63b-7da9-4a0c-b9d5-4a2d2ae772f1\"}\n[2026-05-11 10:17:42] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610915,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f131d63b-7da9-4a0c-b9d5-4a2d2ae772f1\"}\n[2026-05-11 10:17:42] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610915,\"participants\":[{\"id\":997104,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997105,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f131d63b-7da9-4a0c-b9d5-4a2d2ae772f1\"}\n[2026-05-11 10:17:42] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f131d63b-7da9-4a0c-b9d5-4a2d2ae772f1\"}\n[2026-05-11 10:17:42] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f131d63b-7da9-4a0c-b9d5-4a2d2ae772f1\"}\n[2026-05-11 10:17:42] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f131d63b-7da9-4a0c-b9d5-4a2d2ae772f1\"}\n[2026-05-11 10:17:42] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f131d63b-7da9-4a0c-b9d5-4a2d2ae772f1\"}\n[2026-05-11 10:17:42] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f131d63b-7da9-4a0c-b9d5-4a2d2ae772f1\"}\n[2026-05-11 10:17:42] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f131d63b-7da9-4a0c-b9d5-4a2d2ae772f1\"}\n[2026-05-11 10:17:42] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":11} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f131d63b-7da9-4a0c-b9d5-4a2d2ae772f1\"}\n[2026-05-11 10:17:42] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610764,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"93d7f7d1-3a5c-47ce-bc42-1af98a032e7b\"}\n[2026-05-11 10:17:42] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610764} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"93d7f7d1-3a5c-47ce-bc42-1af98a032e7b\"}\n[2026-05-11 10:17:42] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610764,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"93d7f7d1-3a5c-47ce-bc42-1af98a032e7b\"}\n[2026-05-11 10:17:42] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610764,\"participants\":[{\"id\":996951,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996952,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"93d7f7d1-3a5c-47ce-bc42-1af98a032e7b\"}\n[2026-05-11 10:17:42] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"93d7f7d1-3a5c-47ce-bc42-1af98a032e7b\"}\n[2026-05-11 10:17:42] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"93d7f7d1-3a5c-47ce-bc42-1af98a032e7b\"}\n[2026-05-11 10:17:42] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"93d7f7d1-3a5c-47ce-bc42-1af98a032e7b\"}\n[2026-05-11 10:17:42] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"93d7f7d1-3a5c-47ce-bc42-1af98a032e7b\"}\n[2026-05-11 10:17:42] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"93d7f7d1-3a5c-47ce-bc42-1af98a032e7b\"}\n[2026-05-11 10:17:42] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"93d7f7d1-3a5c-47ce-bc42-1af98a032e7b\"}\n[2026-05-11 10:17:42] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":15} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"93d7f7d1-3a5c-47ce-bc42-1af98a032e7b\"}\n[2026-05-11 10:17:42] local.INFO: [ EsUpdateProcessManager ] Finished updating entities in ES {\"worker\":\"\",\"peak_memory\":\"99.73 MB\",\"elapsed_seconds\":0.23,\"update_target\":\"activities\",\"should_iterate_again\":false} {\"correlation_id\":\"4ad05333-9afb-492e-9f0f-b2909ac45b32\",\"trace_id\":\"3d8feb24-b173-4158-b0a4-4cf33af85066\"}\n[2026-05-11 10:17:43] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610490,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"efb63783-8dfd-4c44-805a-c36bcb5e317e\"}\n[2026-05-11 10:17:43] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610490} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"efb63783-8dfd-4c44-805a-c36bcb5e317e\"}\n[2026-05-11 10:17:43] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610490,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"efb63783-8dfd-4c44-805a-c36bcb5e317e\"}\n[2026-05-11 10:17:43] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610490,\"participants\":[{\"id\":996385,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996386,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"efb63783-8dfd-4c44-805a-c36bcb5e317e\"}\n[2026-05-11 10:17:43] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"efb63783-8dfd-4c44-805a-c36bcb5e317e\"}\n[2026-05-11 10:17:43] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"efb63783-8dfd-4c44-805a-c36bcb5e317e\"}\n[2026-05-11 10:17:43] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"efb63783-8dfd-4c44-805a-c36bcb5e317e\"}\n[2026-05-11 10:17:43] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"efb63783-8dfd-4c44-805a-c36bcb5e317e\"}\n[2026-05-11 10:17:43] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"efb63783-8dfd-4c44-805a-c36bcb5e317e\"}\n[2026-05-11 10:17:43] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"efb63783-8dfd-4c44-805a-c36bcb5e317e\"}\n[2026-05-11 10:17:43] local.WARNING: [Hubspot] No retry-after header or policy name found, using default {\"exception_class\":\"SevenShores\\\\Hubspot\\\\Exceptions\\\\BadRequest\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"efb63783-8dfd-4c44-805a-c36bcb5e317e\"}\n[2026-05-11 10:17:43] local.WARNING: [Hubspot] Received 429 from API {\"team_id\":2,\"config_id\":2,\"retry_after\":10,\"policy\":null,\"reason\":\"Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response:\n{\\\"status\\\":\\\"error\\\",\\\"message\\\":\\\"You have reached your secondly limit.\\\",\\\"errorType\\\":\\\"RATE_LIMIT\\\",\\\"correlationId\\\":\\\"019e168a-e (truncated...)\n\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"efb63783-8dfd-4c44-805a-c36bcb5e317e\"}\n[2026-05-11 10:17:43] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":14} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"efb63783-8dfd-4c44-805a-c36bcb5e317e\"}\n[2026-05-11 10:17:43] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610528,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"34f22bc6-50a7-4f6e-96be-552d05a23255\"}\n[2026-05-11 10:17:43] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610528} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"34f22bc6-50a7-4f6e-96be-552d05a23255\"}\n[2026-05-11 10:17:43] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610528,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"34f22bc6-50a7-4f6e-96be-552d05a23255\"}\n[2026-05-11 10:17:43] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610528,\"participants\":[{\"id\":996463,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996464,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"34f22bc6-50a7-4f6e-96be-552d05a23255\"}\n[2026-05-11 10:17:43] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"34f22bc6-50a7-4f6e-96be-552d05a23255\"}\n[2026-05-11 10:17:43] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"34f22bc6-50a7-4f6e-96be-552d05a23255\"}\n[2026-05-11 10:17:43] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"34f22bc6-50a7-4f6e-96be-552d05a23255\"}\n[2026-05-11 10:17:43] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"34f22bc6-50a7-4f6e-96be-552d05a23255\"}\n[2026-05-11 10:17:43] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"34f22bc6-50a7-4f6e-96be-552d05a23255\"}\n[2026-05-11 10:17:43] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"34f22bc6-50a7-4f6e-96be-552d05a23255\"}\n[2026-05-11 10:17:43] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":11} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"34f22bc6-50a7-4f6e-96be-552d05a23255\"}\n[2026-05-11 10:17:43] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610885,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"624ce203-96d1-4009-ae4e-5b6635eff4b0\"}\n[2026-05-11 10:17:43] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610885} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"624ce203-96d1-4009-ae4e-5b6635eff4b0\"}\n[2026-05-11 10:17:43] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610885,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"624ce203-96d1-4009-ae4e-5b6635eff4b0\"}\n[2026-05-11 10:17:43] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610885,\"participants\":[{\"id\":997051,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997052,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"624ce203-96d1-4009-ae4e-5b6635eff4b0\"}\n[2026-05-11 10:17:43] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"624ce203-96d1-4009-ae4e-5b6635eff4b0\"}\n[2026-05-11 10:17:43] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"624ce203-96d1-4009-ae4e-5b6635eff4b0\"}\n[2026-05-11 10:17:43] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"624ce203-96d1-4009-ae4e-5b6635eff4b0\"}\n[2026-05-11 10:17:43] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"624ce203-96d1-4009-ae4e-5b6635eff4b0\"}\n[2026-05-11 10:17:43] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"624ce203-96d1-4009-ae4e-5b6635eff4b0\"}\n[2026-05-11 10:17:43] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"624ce203-96d1-4009-ae4e-5b6635eff4b0\"}\n[2026-05-11 10:17:43] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":12} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"624ce203-96d1-4009-ae4e-5b6635eff4b0\"}\n[2026-05-11 10:17:44] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610451,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"99d1cf07-a91d-4a90-8059-1fe54fb6097a\"}\n[2026-05-11 10:17:44] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610451} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"99d1cf07-a91d-4a90-8059-1fe54fb6097a\"}\n[2026-05-11 10:17:44] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610451,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"99d1cf07-a91d-4a90-8059-1fe54fb6097a\"}\n[2026-05-11 10:17:44] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610451,\"participants\":[{\"id\":996340,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996341,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"99d1cf07-a91d-4a90-8059-1fe54fb6097a\"}\n[2026-05-11 10:17:44] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"99d1cf07-a91d-4a90-8059-1fe54fb6097a\"}\n[2026-05-11 10:17:44] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"99d1cf07-a91d-4a90-8059-1fe54fb6097a\"}\n[2026-05-11 10:17:44] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"99d1cf07-a91d-4a90-8059-1fe54fb6097a\"}\n[2026-05-11 10:17:44] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"99d1cf07-a91d-4a90-8059-1fe54fb6097a\"}\n[2026-05-11 10:17:44] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"99d1cf07-a91d-4a90-8059-1fe54fb6097a\"}\n[2026-05-11 10:17:44] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"99d1cf07-a91d-4a90-8059-1fe54fb6097a\"}\n[2026-05-11 10:17:44] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":13} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"99d1cf07-a91d-4a90-8059-1fe54fb6097a\"}\n[2026-05-11 10:17:44] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614381,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"71db6557-d1a4-488a-bcaa-cefeb41f9f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614381} {\"correlation_id\":\"71db6557-d1a4-488a-bcaa-cefeb41f9f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614381,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"71db6557-d1a4-488a-bcaa-cefeb41f9f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614381,\"participants\":[{\"id\":1002630,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002631,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"71db6557-d1a4-488a-bcaa-cefeb41f9f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"71db6557-d1a4-488a-bcaa-cefeb41f9f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"71db6557-d1a4-488a-bcaa-cefeb41f9f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"71db6557-d1a4-488a-bcaa-cefeb41f9f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"71db6557-d1a4-488a-bcaa-cefeb41f9f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"71db6557-d1a4-488a-bcaa-cefeb41f9f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"71db6557-d1a4-488a-bcaa-cefeb41f9f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":13} {\"correlation_id\":\"71db6557-d1a4-488a-bcaa-cefeb41f9f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610874,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"c4fcf2aa-0846-4e80-b18b-251b2d368949\"}\n[2026-05-11 10:17:44] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610874} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"c4fcf2aa-0846-4e80-b18b-251b2d368949\"}\n[2026-05-11 10:17:44] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610874,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"c4fcf2aa-0846-4e80-b18b-251b2d368949\"}\n[2026-05-11 10:17:44] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610874,\"participants\":[{\"id\":997025,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997026,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"c4fcf2aa-0846-4e80-b18b-251b2d368949\"}\n[2026-05-11 10:17:44] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"c4fcf2aa-0846-4e80-b18b-251b2d368949\"}\n[2026-05-11 10:17:44] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"c4fcf2aa-0846-4e80-b18b-251b2d368949\"}\n[2026-05-11 10:17:44] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"c4fcf2aa-0846-4e80-b18b-251b2d368949\"}\n[2026-05-11 10:17:44] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"c4fcf2aa-0846-4e80-b18b-251b2d368949\"}\n[2026-05-11 10:17:44] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"c4fcf2aa-0846-4e80-b18b-251b2d368949\"}\n[2026-05-11 10:17:44] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"c4fcf2aa-0846-4e80-b18b-251b2d368949\"}\n[2026-05-11 10:17:44] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":10} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"c4fcf2aa-0846-4e80-b18b-251b2d368949\"}\n[2026-05-11 10:17:44] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612560,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"286a6558-1e66-4ffb-b32f-9f823a296d14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612560} {\"correlation_id\":\"286a6558-1e66-4ffb-b32f-9f823a296d14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612560,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"286a6558-1e66-4ffb-b32f-9f823a296d14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612560,\"participants\":[{\"id\":999778,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999779,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"286a6558-1e66-4ffb-b32f-9f823a296d14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"286a6558-1e66-4ffb-b32f-9f823a296d14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"286a6558-1e66-4ffb-b32f-9f823a296d14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"286a6558-1e66-4ffb-b32f-9f823a296d14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"286a6558-1e66-4ffb-b32f-9f823a296d14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"correlation_id\":\"286a6558-1e66-4ffb-b32f-9f823a296d14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"447782589921@txt.staging.jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/447782589921%40txt.staging.jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"correlation_id\":\"286a6558-1e66-4ffb-b32f-9f823a296d14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"correlation_id\":\"286a6558-1e66-4ffb-b32f-9f823a296d14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":15} {\"correlation_id\":\"286a6558-1e66-4ffb-b32f-9f823a296d14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614382,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"c0afdc10-8cad-4dab-9147-5495fc19b7c4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614382} {\"correlation_id\":\"c0afdc10-8cad-4dab-9147-5495fc19b7c4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614382,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"c0afdc10-8cad-4dab-9147-5495fc19b7c4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614382,\"participants\":[{\"id\":1002632,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002633,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"c0afdc10-8cad-4dab-9147-5495fc19b7c4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"c0afdc10-8cad-4dab-9147-5495fc19b7c4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"c0afdc10-8cad-4dab-9147-5495fc19b7c4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"c0afdc10-8cad-4dab-9147-5495fc19b7c4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"c0afdc10-8cad-4dab-9147-5495fc19b7c4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"c0afdc10-8cad-4dab-9147-5495fc19b7c4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"c0afdc10-8cad-4dab-9147-5495fc19b7c4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":12} {\"correlation_id\":\"c0afdc10-8cad-4dab-9147-5495fc19b7c4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610867,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1b88706b-8ac4-431d-8696-8f8766ecae33\"}\n[2026-05-11 10:17:45] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610867} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1b88706b-8ac4-431d-8696-8f8766ecae33\"}\n[2026-05-11 10:17:45] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610867,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1b88706b-8ac4-431d-8696-8f8766ecae33\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610867,\"participants\":[{\"id\":997011,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997012,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1b88706b-8ac4-431d-8696-8f8766ecae33\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1b88706b-8ac4-431d-8696-8f8766ecae33\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1b88706b-8ac4-431d-8696-8f8766ecae33\"}\n[2026-05-11 10:17:45] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1b88706b-8ac4-431d-8696-8f8766ecae33\"}\n[2026-05-11 10:17:45] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1b88706b-8ac4-431d-8696-8f8766ecae33\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1b88706b-8ac4-431d-8696-8f8766ecae33\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1b88706b-8ac4-431d-8696-8f8766ecae33\"}\n[2026-05-11 10:17:45] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":11} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1b88706b-8ac4-431d-8696-8f8766ecae33\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612819,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612819} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612819,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612819,\"participants\":[{\"id\":1000073,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1000074,\"user_id\":261,\"contact_id\":null,\"lead_id\":null},{\"id\":1000075,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: ProspectCache - Searching DB for opportunity by owner {\"account_id\":244,\"contact_id\":4487,\"owner_id\":261} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: ProspectCache - Opportunity DB search results {\"account_id\":244,\"contact_id\":4487,\"opportunity_id\":299} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612819,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"adelina.petrova@jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/adelina.petrova%40jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":15} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612847,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"b4c629ce-833d-484c-8155-4df866fe54cf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612847} {\"correlation_id\":\"b4c629ce-833d-484c-8155-4df866fe54cf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612847,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"b4c629ce-833d-484c-8155-4df866fe54cf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612847,\"participants\":[{\"id\":1000130,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1000131,\"user_id\":261,\"contact_id\":null,\"lead_id\":null},{\"id\":1000151,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null}]} {\"correlation_id\":\"b4c629ce-833d-484c-8155-4df866fe54cf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b4c629ce-833d-484c-8155-4df866fe54cf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b4c629ce-833d-484c-8155-4df866fe54cf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"b4c629ce-833d-484c-8155-4df866fe54cf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"b4c629ce-833d-484c-8155-4df866fe54cf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"correlation_id\":\"b4c629ce-833d-484c-8155-4df866fe54cf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"correlation_id\":\"b4c629ce-833d-484c-8155-4df866fe54cf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":15} {\"correlation_id\":\"b4c629ce-833d-484c-8155-4df866fe54cf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610506,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"168d2aac-7bb8-4249-b62a-e088ef05a5c3\"}\n[2026-05-11 10:17:45] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610506} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"168d2aac-7bb8-4249-b62a-e088ef05a5c3\"}\n[2026-05-11 10:17:45] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610506,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"168d2aac-7bb8-4249-b62a-e088ef05a5c3\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610506,\"participants\":[{\"id\":996419,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996420,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"168d2aac-7bb8-4249-b62a-e088ef05a5c3\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"168d2aac-7bb8-4249-b62a-e088ef05a5c3\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"168d2aac-7bb8-4249-b62a-e088ef05a5c3\"}\n[2026-05-11 10:17:45] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"168d2aac-7bb8-4249-b62a-e088ef05a5c3\"}\n[2026-05-11 10:17:45] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"168d2aac-7bb8-4249-b62a-e088ef05a5c3\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"168d2aac-7bb8-4249-b62a-e088ef05a5c3\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"168d2aac-7bb8-4249-b62a-e088ef05a5c3\"}\n[2026-05-11 10:17:45] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":12} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"168d2aac-7bb8-4249-b62a-e088ef05a5c3\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610497,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"067b89fc-5453-49ae-a3fa-5dfdb487c294\"}\n[2026-05-11 10:17:45] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610497} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"067b89fc-5453-49ae-a3fa-5dfdb487c294\"}\n[2026-05-11 10:17:45] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610497,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"067b89fc-5453-49ae-a3fa-5dfdb487c294\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610497,\"participants\":[{\"id\":996401,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996402,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"067b89fc-5453-49ae-a3fa-5dfdb487c294\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"067b89fc-5453-49ae-a3fa-5dfdb487c294\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"067b89fc-5453-49ae-a3fa-5dfdb487c294\"}\n[2026-05-11 10:17:45] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"067b89fc-5453-49ae-a3fa-5dfdb487c294\"}\n[2026-05-11 10:17:45] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"067b89fc-5453-49ae-a3fa-5dfdb487c294\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"067b89fc-5453-49ae-a3fa-5dfdb487c294\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"067b89fc-5453-49ae-a3fa-5dfdb487c294\"}\n[2026-05-11 10:17:45] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":10} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"067b89fc-5453-49ae-a3fa-5dfdb487c294\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610617,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e2d3538d-9a14-45c4-b068-84b3732061df\"}\n[2026-05-11 10:17:45] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610617} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e2d3538d-9a14-45c4-b068-84b3732061df\"}\n[2026-05-11 10:17:45] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610617,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e2d3538d-9a14-45c4-b068-84b3732061df\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610617,\"participants\":[{\"id\":996641,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996642,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e2d3538d-9a14-45c4-b068-84b3732061df\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e2d3538d-9a14-45c4-b068-84b3732061df\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e2d3538d-9a14-45c4-b068-84b3732061df\"}\n[2026-05-11 10:17:45] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e2d3538d-9a14-45c4-b068-84b3732061df\"}\n[2026-05-11 10:17:45] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e2d3538d-9a14-45c4-b068-84b3732061df\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e2d3538d-9a14-45c4-b068-84b3732061df\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e2d3538d-9a14-45c4-b068-84b3732061df\"}\n[2026-05-11 10:17:45] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":10} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e2d3538d-9a14-45c4-b068-84b3732061df\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610403,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e7285c6c-728d-4284-b885-7e9e9df72706\"}\n[2026-05-11 10:17:45] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610403} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e7285c6c-728d-4284-b885-7e9e9df72706\"}\n[2026-05-11 10:17:45] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610403,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e7285c6c-728d-4284-b885-7e9e9df72706\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610403,\"participants\":[{\"id\":996282,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996283,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e7285c6c-728d-4284-b885-7e9e9df72706\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e7285c6c-728d-4284-b885-7e9e9df72706\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e7285c6c-728d-4284-b885-7e9e9df72706\"}\n[2026-05-11 10:17:45] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e7285c6c-728d-4284-b885-7e9e9df72706\"}\n[2026-05-11 10:17:45] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e7285c6c-728d-4284-b885-7e9e9df72706\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e7285c6c-728d-4284-b885-7e9e9df72706\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e7285c6c-728d-4284-b885-7e9e9df72706\"}\n[2026-05-11 10:17:45] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":12} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e7285c6c-728d-4284-b885-7e9e9df72706\"}\n[2026-05-11 10:17:46] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614378,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":6167,\"account_id\":null,\"opportunity_id\":null,\"stage_id\":null}} {\"correlation_id\":\"5463b5ad-2286-4568-8f68-76b82d8a4c54\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:46] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614378} {\"correlation_id\":\"5463b5ad-2286-4568-8f68-76b82d8a4c54\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:46] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614378,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"5463b5ad-2286-4568-8f68-76b82d8a4c54\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:46] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614378,\"participants\":[{\"id\":1002623,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002624,\"user_id\":null,\"contact_id\":6167,\"lead_id\":null},{\"id\":1002625,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"5463b5ad-2286-4568-8f68-76b82d8a4c54\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:46] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"5463b5ad-2286-4568-8f68-76b82d8a4c54\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:46] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"5463b5ad-2286-4568-8f68-76b82d8a4c54\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:46] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"5463b5ad-2286-4568-8f68-76b82d8a4c54\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:46] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"5463b5ad-2286-4568-8f68-76b82d8a4c54\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:46] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"5463b5ad-2286-4568-8f68-76b82d8a4c54\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:46] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"5463b5ad-2286-4568-8f68-76b82d8a4c54\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":15} {\"correlation_id\":\"5463b5ad-2286-4568-8f68-76b82d8a4c54\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612561,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"ca6930a0-aebc-4338-856e-6a439a838639\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612561} {\"correlation_id\":\"ca6930a0-aebc-4338-856e-6a439a838639\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612561,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"ca6930a0-aebc-4338-856e-6a439a838639\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612561,\"participants\":[{\"id\":999780,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999781,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"ca6930a0-aebc-4338-856e-6a439a838639\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"ca6930a0-aebc-4338-856e-6a439a838639\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"ca6930a0-aebc-4338-856e-6a439a838639\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"ca6930a0-aebc-4338-856e-6a439a838639\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"ca6930a0-aebc-4338-856e-6a439a838639\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612561,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"ca6930a0-aebc-4338-856e-6a439a838639\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"447700174614.447782589921.OeREojLVnk@txt.staging.jiminny.com\"} {\"correlation_id\":\"ca6930a0-aebc-4338-856e-6a439a838639\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"447700174614.447782589921.OeREojLVnk@txt.staging.jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/447700174614.447782589921.OeREojLVnk%40txt.staging.jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"correlation_id\":\"ca6930a0-aebc-4338-856e-6a439a838639\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"447700174614.447782589921.OeREojLVnk@txt.staging.jiminny.com\"} {\"correlation_id\":\"ca6930a0-aebc-4338-856e-6a439a838639\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"ca6930a0-aebc-4338-856e-6a439a838639\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610438,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7721c535-7311-417a-b30a-1286a84e037b\"}\n[2026-05-11 10:17:47] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610438} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7721c535-7311-417a-b30a-1286a84e037b\"}\n[2026-05-11 10:17:47] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610438,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7721c535-7311-417a-b30a-1286a84e037b\"}\n[2026-05-11 10:17:47] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610438,\"participants\":[{\"id\":996320,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996321,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7721c535-7311-417a-b30a-1286a84e037b\"}\n[2026-05-11 10:17:47] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7721c535-7311-417a-b30a-1286a84e037b\"}\n[2026-05-11 10:17:47] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7721c535-7311-417a-b30a-1286a84e037b\"}\n[2026-05-11 10:17:47] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7721c535-7311-417a-b30a-1286a84e037b\"}\n[2026-05-11 10:17:47] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7721c535-7311-417a-b30a-1286a84e037b\"}\n[2026-05-11 10:17:47] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7721c535-7311-417a-b30a-1286a84e037b\"}\n[2026-05-11 10:17:47] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7721c535-7311-417a-b30a-1286a84e037b\"}\n[2026-05-11 10:17:47] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":12} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7721c535-7311-417a-b30a-1286a84e037b\"}\n[2026-05-11 10:17:47] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614436,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"e20af459-b149-4a19-8ef6-4444b4cee8f9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614436} {\"correlation_id\":\"e20af459-b149-4a19-8ef6-4444b4cee8f9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614436,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"e20af459-b149-4a19-8ef6-4444b4cee8f9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614436,\"participants\":[{\"id\":1002751,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002752,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"e20af459-b149-4a19-8ef6-4444b4cee8f9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"e20af459-b149-4a19-8ef6-4444b4cee8f9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"e20af459-b149-4a19-8ef6-4444b4cee8f9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"e20af459-b149-4a19-8ef6-4444b4cee8f9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"e20af459-b149-4a19-8ef6-4444b4cee8f9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"e20af459-b149-4a19-8ef6-4444b4cee8f9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"e20af459-b149-4a19-8ef6-4444b4cee8f9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"e20af459-b149-4a19-8ef6-4444b4cee8f9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610462,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90f3fc25-e34d-4c3a-b35c-84317a633c78\"}\n[2026-05-11 10:17:47] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610462} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90f3fc25-e34d-4c3a-b35c-84317a633c78\"}\n[2026-05-11 10:17:47] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610462,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90f3fc25-e34d-4c3a-b35c-84317a633c78\"}\n[2026-05-11 10:17:47] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610462,\"participants\":[{\"id\":996353,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996354,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90f3fc25-e34d-4c3a-b35c-84317a633c78\"}\n[2026-05-11 10:17:47] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90f3fc25-e34d-4c3a-b35c-84317a633c78\"}\n[2026-05-11 10:17:47] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90f3fc25-e34d-4c3a-b35c-84317a633c78\"}\n[2026-05-11 10:17:47] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90f3fc25-e34d-4c3a-b35c-84317a633c78\"}\n[2026-05-11 10:17:47] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90f3fc25-e34d-4c3a-b35c-84317a633c78\"}\n[2026-05-11 10:17:47] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90f3fc25-e34d-4c3a-b35c-84317a633c78\"}\n[2026-05-11 10:17:47] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90f3fc25-e34d-4c3a-b35c-84317a633c78\"}\n[2026-05-11 10:17:47] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":14} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90f3fc25-e34d-4c3a-b35c-84317a633c78\"}\n[2026-05-11 10:17:47] local.INFO: [ EsUpdateProcessManager ] Finished updating entities in ES {\"worker\":\"\",\"peak_memory\":\"99.73 MB\",\"elapsed_seconds\":0.21,\"update_target\":\"activities\",\"should_iterate_again\":false} {\"correlation_id\":\"4ad05333-9afb-492e-9f0f-b2909ac45b32\",\"trace_id\":\"3d8feb24-b173-4158-b0a4-4cf33af85066\"}\n[2026-05-11 10:17:48] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610470,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6264c9dd-ba42-4c8f-a21f-3dffeb0c31c6\"}\n[2026-05-11 10:17:48] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610470} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6264c9dd-ba42-4c8f-a21f-3dffeb0c31c6\"}\n[2026-05-11 10:17:48] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610470,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6264c9dd-ba42-4c8f-a21f-3dffeb0c31c6\"}\n[2026-05-11 10:17:48] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610470,\"participants\":[{\"id\":996369,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996370,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6264c9dd-ba42-4c8f-a21f-3dffeb0c31c6\"}\n[2026-05-11 10:17:48] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6264c9dd-ba42-4c8f-a21f-3dffeb0c31c6\"}\n[2026-05-11 10:17:48] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6264c9dd-ba42-4c8f-a21f-3dffeb0c31c6\"}\n[2026-05-11 10:17:48] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6264c9dd-ba42-4c8f-a21f-3dffeb0c31c6\"}\n[2026-05-11 10:17:48] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6264c9dd-ba42-4c8f-a21f-3dffeb0c31c6\"}\n[2026-05-11 10:17:48] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6264c9dd-ba42-4c8f-a21f-3dffeb0c31c6\"}\n[2026-05-11 10:17:48] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6264c9dd-ba42-4c8f-a21f-3dffeb0c31c6\"}\n[2026-05-11 10:17:48] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":12} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6264c9dd-ba42-4c8f-a21f-3dffeb0c31c6\"}\n[2026-05-11 10:17:48] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":615092,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"64b7efd5-f92f-42b8-95ba-9a9e76fbb676\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":615092} {\"correlation_id\":\"64b7efd5-f92f-42b8-95ba-9a9e76fbb676\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":615092,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"64b7efd5-f92f-42b8-95ba-9a9e76fbb676\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":615092,\"participants\":[{\"id\":1004102,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1004103,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"64b7efd5-f92f-42b8-95ba-9a9e76fbb676\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"64b7efd5-f92f-42b8-95ba-9a9e76fbb676\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"64b7efd5-f92f-42b8-95ba-9a9e76fbb676\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"64b7efd5-f92f-42b8-95ba-9a9e76fbb676\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"64b7efd5-f92f-42b8-95ba-9a9e76fbb676\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"64b7efd5-f92f-42b8-95ba-9a9e76fbb676\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"64b7efd5-f92f-42b8-95ba-9a9e76fbb676\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"64b7efd5-f92f-42b8-95ba-9a9e76fbb676\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612562,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"aa8720ba-c5e3-4d7e-a7c3-697da34a195e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612562} {\"correlation_id\":\"aa8720ba-c5e3-4d7e-a7c3-697da34a195e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612562,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"aa8720ba-c5e3-4d7e-a7c3-697da34a195e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612562,\"participants\":[{\"id\":999782,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999783,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"aa8720ba-c5e3-4d7e-a7c3-697da34a195e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"aa8720ba-c5e3-4d7e-a7c3-697da34a195e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"aa8720ba-c5e3-4d7e-a7c3-697da34a195e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"aa8720ba-c5e3-4d7e-a7c3-697da34a195e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"aa8720ba-c5e3-4d7e-a7c3-697da34a195e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"correlation_id\":\"aa8720ba-c5e3-4d7e-a7c3-697da34a195e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"correlation_id\":\"aa8720ba-c5e3-4d7e-a7c3-697da34a195e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"aa8720ba-c5e3-4d7e-a7c3-697da34a195e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610900,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"1abedcde-ca97-4113-b4a6-60a45a16f9d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610900} {\"correlation_id\":\"1abedcde-ca97-4113-b4a6-60a45a16f9d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610900,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"1abedcde-ca97-4113-b4a6-60a45a16f9d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610900,\"participants\":[{\"id\":997081,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997082,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"1abedcde-ca97-4113-b4a6-60a45a16f9d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"1abedcde-ca97-4113-b4a6-60a45a16f9d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"1abedcde-ca97-4113-b4a6-60a45a16f9d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"1abedcde-ca97-4113-b4a6-60a45a16f9d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"1abedcde-ca97-4113-b4a6-60a45a16f9d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"1abedcde-ca97-4113-b4a6-60a45a16f9d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"1abedcde-ca97-4113-b4a6-60a45a16f9d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":12} {\"correlation_id\":\"1abedcde-ca97-4113-b4a6-60a45a16f9d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610935,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"d4390ffe-1359-41f6-9feb-f0bfbfdafc61\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610935} {\"correlation_id\":\"d4390ffe-1359-41f6-9feb-f0bfbfdafc61\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610935,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"d4390ffe-1359-41f6-9feb-f0bfbfdafc61\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610935,\"participants\":[{\"id\":997141,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997142,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"d4390ffe-1359-41f6-9feb-f0bfbfdafc61\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"d4390ffe-1359-41f6-9feb-f0bfbfdafc61\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"d4390ffe-1359-41f6-9feb-f0bfbfdafc61\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"d4390ffe-1359-41f6-9feb-f0bfbfdafc61\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"d4390ffe-1359-41f6-9feb-f0bfbfdafc61\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"d4390ffe-1359-41f6-9feb-f0bfbfdafc61\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"d4390ffe-1359-41f6-9feb-f0bfbfdafc61\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":12} {\"correlation_id\":\"d4390ffe-1359-41f6-9feb-f0bfbfdafc61\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611451,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"42a128d7-d841-4c03-a6c0-7b9fa918ec1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611451} {\"correlation_id\":\"42a128d7-d841-4c03-a6c0-7b9fa918ec1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611451,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"42a128d7-d841-4c03-a6c0-7b9fa918ec1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611451,\"participants\":[{\"id\":997955,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997956,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"42a128d7-d841-4c03-a6c0-7b9fa918ec1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"42a128d7-d841-4c03-a6c0-7b9fa918ec1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"42a128d7-d841-4c03-a6c0-7b9fa918ec1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"42a128d7-d841-4c03-a6c0-7b9fa918ec1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"42a128d7-d841-4c03-a6c0-7b9fa918ec1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"42a128d7-d841-4c03-a6c0-7b9fa918ec1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"42a128d7-d841-4c03-a6c0-7b9fa918ec1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"42a128d7-d841-4c03-a6c0-7b9fa918ec1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612340,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"68eaf196-29ca-48a3-8e46-5bf37620dd08\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612340} {\"correlation_id\":\"68eaf196-29ca-48a3-8e46-5bf37620dd08\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612340,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"68eaf196-29ca-48a3-8e46-5bf37620dd08\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612340,\"participants\":[{\"id\":999516,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999517,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999518,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999519,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"68eaf196-29ca-48a3-8e46-5bf37620dd08\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"68eaf196-29ca-48a3-8e46-5bf37620dd08\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"68eaf196-29ca-48a3-8e46-5bf37620dd08\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"68eaf196-29ca-48a3-8e46-5bf37620dd08\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"68eaf196-29ca-48a3-8e46-5bf37620dd08\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"68eaf196-29ca-48a3-8e46-5bf37620dd08\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612340,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"68eaf196-29ca-48a3-8e46-5bf37620dd08\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":15} {\"correlation_id\":\"68eaf196-29ca-48a3-8e46-5bf37620dd08\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610426,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f997c306-a176-4f3a-8699-d9cd083d6993\"}\n[2026-05-11 10:17:49] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610426} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f997c306-a176-4f3a-8699-d9cd083d6993\"}\n[2026-05-11 10:17:49] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610426,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f997c306-a176-4f3a-8699-d9cd083d6993\"}\n[2026-05-11 10:17:49] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610426,\"participants\":[{\"id\":996306,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996307,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f997c306-a176-4f3a-8699-d9cd083d6993\"}\n[2026-05-11 10:17:49] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f997c306-a176-4f3a-8699-d9cd083d6993\"}\n[2026-05-11 10:17:49] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f997c306-a176-4f3a-8699-d9cd083d6993\"}\n[2026-05-11 10:17:49] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f997c306-a176-4f3a-8699-d9cd083d6993\"}\n[2026-05-11 10:17:49] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f997c306-a176-4f3a-8699-d9cd083d6993\"}\n[2026-05-11 10:17:49] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f997c306-a176-4f3a-8699-d9cd083d6993\"}\n[2026-05-11 10:17:49] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f997c306-a176-4f3a-8699-d9cd083d6993\"}\n[2026-05-11 10:17:49] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":11} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f997c306-a176-4f3a-8699-d9cd083d6993\"}\n[2026-05-11 10:17:49] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612336,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"18efa24c-257e-4842-af7d-5ec20872ab02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612336} {\"correlation_id\":\"18efa24c-257e-4842-af7d-5ec20872ab02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612336,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"18efa24c-257e-4842-af7d-5ec20872ab02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612336,\"participants\":[{\"id\":999508,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999509,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999512,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999513,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"18efa24c-257e-4842-af7d-5ec20872ab02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"18efa24c-257e-4842-af7d-5ec20872ab02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"18efa24c-257e-4842-af7d-5ec20872ab02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"18efa24c-257e-4842-af7d-5ec20872ab02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"18efa24c-257e-4842-af7d-5ec20872ab02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"18efa24c-257e-4842-af7d-5ec20872ab02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612336,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"18efa24c-257e-4842-af7d-5ec20872ab02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"18efa24c-257e-4842-af7d-5ec20872ab02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612360,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"af4fe4e8-53c1-4339-8100-49dadac0f280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612360} {\"correlation_id\":\"af4fe4e8-53c1-4339-8100-49dadac0f280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612360,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"af4fe4e8-53c1-4339-8100-49dadac0f280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612360,\"participants\":[{\"id\":999552,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999553,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999565,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"af4fe4e8-53c1-4339-8100-49dadac0f280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"af4fe4e8-53c1-4339-8100-49dadac0f280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"af4fe4e8-53c1-4339-8100-49dadac0f280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"af4fe4e8-53c1-4339-8100-49dadac0f280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"af4fe4e8-53c1-4339-8100-49dadac0f280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"af4fe4e8-53c1-4339-8100-49dadac0f280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612360,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"af4fe4e8-53c1-4339-8100-49dadac0f280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":13} {\"correlation_id\":\"af4fe4e8-53c1-4339-8100-49dadac0f280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612339,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"68a001e2-a116-4b5d-b8e7-902d08ada842\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612339} {\"correlation_id\":\"68a001e2-a116-4b5d-b8e7-902d08ada842\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612339,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"68a001e2-a116-4b5d-b8e7-902d08ada842\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612339,\"participants\":[{\"id\":999514,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999515,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999540,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"68a001e2-a116-4b5d-b8e7-902d08ada842\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"68a001e2-a116-4b5d-b8e7-902d08ada842\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"68a001e2-a116-4b5d-b8e7-902d08ada842\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"68a001e2-a116-4b5d-b8e7-902d08ada842\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"68a001e2-a116-4b5d-b8e7-902d08ada842\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"68a001e2-a116-4b5d-b8e7-902d08ada842\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612339,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"68a001e2-a116-4b5d-b8e7-902d08ada842\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":13} {\"correlation_id\":\"68a001e2-a116-4b5d-b8e7-902d08ada842\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611087,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"19bb8a09-8a89-4524-bfc1-e972923a1f2b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611087} {\"correlation_id\":\"19bb8a09-8a89-4524-bfc1-e972923a1f2b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611087,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"19bb8a09-8a89-4524-bfc1-e972923a1f2b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611087,\"participants\":[{\"id\":997368,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997369,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"19bb8a09-8a89-4524-bfc1-e972923a1f2b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"19bb8a09-8a89-4524-bfc1-e972923a1f2b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"19bb8a09-8a89-4524-bfc1-e972923a1f2b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"19bb8a09-8a89-4524-bfc1-e972923a1f2b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"19bb8a09-8a89-4524-bfc1-e972923a1f2b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"19bb8a09-8a89-4524-bfc1-e972923a1f2b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"19bb8a09-8a89-4524-bfc1-e972923a1f2b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":15} {\"correlation_id\":\"19bb8a09-8a89-4524-bfc1-e972923a1f2b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611455,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"dd53be6e-a456-46da-ab7c-c2988301922f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611455} {\"correlation_id\":\"dd53be6e-a456-46da-ab7c-c2988301922f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611455,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"dd53be6e-a456-46da-ab7c-c2988301922f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611455,\"participants\":[{\"id\":997961,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997962,\"user_id\":1460,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"dd53be6e-a456-46da-ab7c-c2988301922f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"dd53be6e-a456-46da-ab7c-c2988301922f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"dd53be6e-a456-46da-ab7c-c2988301922f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"dd53be6e-a456-46da-ab7c-c2988301922f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"dd53be6e-a456-46da-ab7c-c2988301922f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"dd53be6e-a456-46da-ab7c-c2988301922f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"dd53be6e-a456-46da-ab7c-c2988301922f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":13} {\"correlation_id\":\"dd53be6e-a456-46da-ab7c-c2988301922f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611076,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"4d0438c5-9dc4-4b93-b643-6417ac75f31a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611076} {\"correlation_id\":\"4d0438c5-9dc4-4b93-b643-6417ac75f31a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611076,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"4d0438c5-9dc4-4b93-b643-6417ac75f31a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611076,\"participants\":[{\"id\":997346,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997347,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"4d0438c5-9dc4-4b93-b643-6417ac75f31a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4d0438c5-9dc4-4b93-b643-6417ac75f31a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4d0438c5-9dc4-4b93-b643-6417ac75f31a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"4d0438c5-9dc4-4b93-b643-6417ac75f31a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"4d0438c5-9dc4-4b93-b643-6417ac75f31a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"4d0438c5-9dc4-4b93-b643-6417ac75f31a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"4d0438c5-9dc4-4b93-b643-6417ac75f31a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"4d0438c5-9dc4-4b93-b643-6417ac75f31a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610539,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"5b1bde17-34b2-4c96-a240-52c83ddc5c93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610539} {\"correlation_id\":\"5b1bde17-34b2-4c96-a240-52c83ddc5c93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610539,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"5b1bde17-34b2-4c96-a240-52c83ddc5c93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610539,\"participants\":[{\"id\":996485,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996486,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"5b1bde17-34b2-4c96-a240-52c83ddc5c93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"5b1bde17-34b2-4c96-a240-52c83ddc5c93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"5b1bde17-34b2-4c96-a240-52c83ddc5c93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"5b1bde17-34b2-4c96-a240-52c83ddc5c93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"5b1bde17-34b2-4c96-a240-52c83ddc5c93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"5b1bde17-34b2-4c96-a240-52c83ddc5c93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"5b1bde17-34b2-4c96-a240-52c83ddc5c93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [ EsUpdateProcessManager ] Finished updating entities in ES {\"worker\":\"\",\"peak_memory\":\"99.73 MB\",\"elapsed_seconds\":1.19,\"update_target\":\"activities\",\"should_iterate_again\":false} {\"correlation_id\":\"4ad05333-9afb-492e-9f0f-b2909ac45b32\",\"trace_id\":\"3d8feb24-b173-4158-b0a4-4cf33af85066\"}\n[2026-05-11 10:17:53] local.WARNING: [Hubspot] No retry-after header or policy name found, using default {\"exception_class\":\"SevenShores\\\\Hubspot\\\\Exceptions\\\\BadRequest\"} {\"correlation_id\":\"5b1bde17-34b2-4c96-a240-52c83ddc5c93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.WARNING: [Hubspot] Received 429 from API {\"team_id\":2,\"config_id\":2,\"retry_after\":10,\"policy\":null,\"reason\":\"Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response:\n{\\\"status\\\":\\\"error\\\",\\\"message\\\":\\\"You have reached your secondly limit.\\\",\\\"errorType\\\":\\\"RATE_LIMIT\\\",\\\"correlationId\\\":\\\"019e168b-1 (truncated...)\n\"} {\"correlation_id\":\"5b1bde17-34b2-4c96-a240-52c83ddc5c93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"5b1bde17-34b2-4c96-a240-52c83ddc5c93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610915,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"88d5107a-d1a9-4def-8f1f-6ff8bea40516\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610915} {\"correlation_id\":\"88d5107a-d1a9-4def-8f1f-6ff8bea40516\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610915,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"88d5107a-d1a9-4def-8f1f-6ff8bea40516\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610915,\"participants\":[{\"id\":997104,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997105,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"88d5107a-d1a9-4def-8f1f-6ff8bea40516\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"88d5107a-d1a9-4def-8f1f-6ff8bea40516\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"88d5107a-d1a9-4def-8f1f-6ff8bea40516\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"88d5107a-d1a9-4def-8f1f-6ff8bea40516\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"88d5107a-d1a9-4def-8f1f-6ff8bea40516\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"88d5107a-d1a9-4def-8f1f-6ff8bea40516\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"88d5107a-d1a9-4def-8f1f-6ff8bea40516\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":12} {\"correlation_id\":\"88d5107a-d1a9-4def-8f1f-6ff8bea40516\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610878,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"9eb70001-f31f-427d-9ecb-d42969509f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610878} {\"correlation_id\":\"9eb70001-f31f-427d-9ecb-d42969509f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610878,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"9eb70001-f31f-427d-9ecb-d42969509f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610878,\"participants\":[{\"id\":997035,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997036,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"9eb70001-f31f-427d-9ecb-d42969509f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"9eb70001-f31f-427d-9ecb-d42969509f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"9eb70001-f31f-427d-9ecb-d42969509f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"9eb70001-f31f-427d-9ecb-d42969509f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"9eb70001-f31f-427d-9ecb-d42969509f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"9eb70001-f31f-427d-9ecb-d42969509f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"9eb70001-f31f-427d-9ecb-d42969509f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"9eb70001-f31f-427d-9ecb-d42969509f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610528,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"b291b19d-e631-4390-a8ce-49431d5f566f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610528} {\"correlation_id\":\"b291b19d-e631-4390-a8ce-49431d5f566f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610528,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"b291b19d-e631-4390-a8ce-49431d5f566f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610528,\"participants\":[{\"id\":996463,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996464,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"b291b19d-e631-4390-a8ce-49431d5f566f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b291b19d-e631-4390-a8ce-49431d5f566f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b291b19d-e631-4390-a8ce-49431d5f566f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"b291b19d-e631-4390-a8ce-49431d5f566f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"b291b19d-e631-4390-a8ce-49431d5f566f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"b291b19d-e631-4390-a8ce-49431d5f566f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"b291b19d-e631-4390-a8ce-49431d5f566f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"b291b19d-e631-4390-a8ce-49431d5f566f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610874,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"4b8fb89e-a1a0-4894-81d9-5d1e86570512\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610874} {\"correlation_id\":\"4b8fb89e-a1a0-4894-81d9-5d1e86570512\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610874,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"4b8fb89e-a1a0-4894-81d9-5d1e86570512\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610874,\"participants\":[{\"id\":997025,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997026,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"4b8fb89e-a1a0-4894-81d9-5d1e86570512\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4b8fb89e-a1a0-4894-81d9-5d1e86570512\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4b8fb89e-a1a0-4894-81d9-5d1e86570512\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"4b8fb89e-a1a0-4894-81d9-5d1e86570512\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"4b8fb89e-a1a0-4894-81d9-5d1e86570512\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"4b8fb89e-a1a0-4894-81d9-5d1e86570512\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"4b8fb89e-a1a0-4894-81d9-5d1e86570512\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"4b8fb89e-a1a0-4894-81d9-5d1e86570512\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610497,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"f27f33ba-8caa-49a5-9cad-cd8293e9a7db\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610497} {\"correlation_id\":\"f27f33ba-8caa-49a5-9cad-cd8293e9a7db\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610497,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"f27f33ba-8caa-49a5-9cad-cd8293e9a7db\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610497,\"participants\":[{\"id\":996401,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996402,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"f27f33ba-8caa-49a5-9cad-cd8293e9a7db\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"f27f33ba-8caa-49a5-9cad-cd8293e9a7db\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"f27f33ba-8caa-49a5-9cad-cd8293e9a7db\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"f27f33ba-8caa-49a5-9cad-cd8293e9a7db\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"f27f33ba-8caa-49a5-9cad-cd8293e9a7db\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"f27f33ba-8caa-49a5-9cad-cd8293e9a7db\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"f27f33ba-8caa-49a5-9cad-cd8293e9a7db\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":12} {\"correlation_id\":\"f27f33ba-8caa-49a5-9cad-cd8293e9a7db\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610617,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"af6121c1-ef51-49a6-acda-bb121812831a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610617} {\"correlation_id\":\"af6121c1-ef51-49a6-acda-bb121812831a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610617,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"af6121c1-ef51-49a6-acda-bb121812831a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610617,\"participants\":[{\"id\":996641,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996642,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"af6121c1-ef51-49a6-acda-bb121812831a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"af6121c1-ef51-49a6-acda-bb121812831a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"af6121c1-ef51-49a6-acda-bb121812831a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"af6121c1-ef51-49a6-acda-bb121812831a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"af6121c1-ef51-49a6-acda-bb121812831a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"af6121c1-ef51-49a6-acda-bb121812831a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"af6121c1-ef51-49a6-acda-bb121812831a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"af6121c1-ef51-49a6-acda-bb121812831a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610885,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"7c89eb2a-2a39-463f-abad-6b13e5fed935\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610885} {\"correlation_id\":\"7c89eb2a-2a39-463f-abad-6b13e5fed935\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610885,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"7c89eb2a-2a39-463f-abad-6b13e5fed935\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610885,\"participants\":[{\"id\":997051,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997052,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"7c89eb2a-2a39-463f-abad-6b13e5fed935\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"7c89eb2a-2a39-463f-abad-6b13e5fed935\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"7c89eb2a-2a39-463f-abad-6b13e5fed935\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"7c89eb2a-2a39-463f-abad-6b13e5fed935\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"7c89eb2a-2a39-463f-abad-6b13e5fed935\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"7c89eb2a-2a39-463f-abad-6b13e5fed935\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"7c89eb2a-2a39-463f-abad-6b13e5fed935\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":13} {\"correlation_id\":\"7c89eb2a-2a39-463f-abad-6b13e5fed935\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:56] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610867,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"9c37e4f5-1e21-4f96-86d0-2d8f2ce76d49\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:56] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610867} {\"correlation_id\":\"9c37e4f5-1e21-4f96-86d0-2d8f2ce76d49\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:56] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610867,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"9c37e4f5-1e21-4f96-86d0-2d8f2ce76d49\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:56] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610867,\"participants\":[{\"id\":997011,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997012,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"9c37e4f5-1e21-4f96-86d0-2d8f2ce76d49\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:56] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"9c37e4f5-1e21-4f96-86d0-2d8f2ce76d49\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:56] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"9c37e4f5-1e21-4f96-86d0-2d8f2ce76d49\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:56] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"9c37e4f5-1e21-4f96-86d0-2d8f2ce76d49\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:56] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"9c37e4f5-1e21-4f96-86d0-2d8f2ce76d49\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:56] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"9c37e4f5-1e21-4f96-86d0-2d8f2ce76d49\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:56] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"9c37e4f5-1e21-4f96-86d0-2d8f2ce76d49\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:56] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":12} {\"correlation_id\":\"9c37e4f5-1e21-4f96-86d0-2d8f2ce76d49\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:57] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610490,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"5a0ad4cc-8cdd-4f1e-8bae-a70a2f7b7280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:57] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610490} {\"correlation_id\":\"5a0ad4cc-8cdd-4f1e-8bae-a70a2f7b7280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:57] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610490,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"5a0ad4cc-8cdd-4f1e-8bae-a70a2f7b7280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:57] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610490,\"participants\":[{\"id\":996385,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996386,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"5a0ad4cc-8cdd-4f1e-8bae-a70a2f7b7280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:57] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"5a0ad4cc-8cdd-4f1e-8bae-a70a2f7b7280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:57] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"5a0ad4cc-8cdd-4f1e-8bae-a70a2f7b7280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:57] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"5a0ad4cc-8cdd-4f1e-8bae-a70a2f7b7280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:57] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"5a0ad4cc-8cdd-4f1e-8bae-a70a2f7b7280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:57] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"5a0ad4cc-8cdd-4f1e-8bae-a70a2f7b7280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:57] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"support@staging.jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/support%40staging.jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"correlation_id\":\"5a0ad4cc-8cdd-4f1e-8bae-a70a2f7b7280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:57] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"5a0ad4cc-8cdd-4f1e-8bae-a70a2f7b7280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:57] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"5a0ad4cc-8cdd-4f1e-8bae-a70a2f7b7280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:57] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610451,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"9884d6bc-6966-4c2b-b123-bd6bff97b920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:57] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610451} {\"correlation_id\":\"9884d6bc-6966-4c2b-b123-bd6bff97b920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:57] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610451,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"9884d6bc-6966-4c2b-b123-bd6bff97b920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610451,\"participants\":[{\"id\":996340,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996341,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"9884d6bc-6966-4c2b-b123-bd6bff97b920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"9884d6bc-6966-4c2b-b123-bd6bff97b920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"9884d6bc-6966-4c2b-b123-bd6bff97b920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"9884d6bc-6966-4c2b-b123-bd6bff97b920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"9884d6bc-6966-4c2b-b123-bd6bff97b920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"9884d6bc-6966-4c2b-b123-bd6bff97b920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"9884d6bc-6966-4c2b-b123-bd6bff97b920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"9884d6bc-6966-4c2b-b123-bd6bff97b920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614381,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"a7f9bc7e-977e-4032-820f-1e0b80c6214f\"}\n[2026-05-11 10:17:58] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614381} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"a7f9bc7e-977e-4032-820f-1e0b80c6214f\"}\n[2026-05-11 10:17:58] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614381,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"a7f9bc7e-977e-4032-820f-1e0b80c6214f\"}\n[2026-05-11 10:17:58] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614381,\"participants\":[{\"id\":1002630,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002631,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"a7f9bc7e-977e-4032-820f-1e0b80c6214f\"}\n[2026-05-11 10:17:58] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"a7f9bc7e-977e-4032-820f-1e0b80c6214f\"}\n[2026-05-11 10:17:58] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"a7f9bc7e-977e-4032-820f-1e0b80c6214f\"}\n[2026-05-11 10:17:58] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"a7f9bc7e-977e-4032-820f-1e0b80c6214f\"}\n[2026-05-11 10:17:58] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"a7f9bc7e-977e-4032-820f-1e0b80c6214f\"}\n[2026-05-11 10:17:58] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"a7f9bc7e-977e-4032-820f-1e0b80c6214f\"}\n[2026-05-11 10:17:58] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"a7f9bc7e-977e-4032-820f-1e0b80c6214f\"}\n[2026-05-11 10:17:58] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610764,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"4674593f-9f44-4f03-8474-ff0a7926a543\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610764} {\"correlation_id\":\"4674593f-9f44-4f03-8474-ff0a7926a543\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610764,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"4674593f-9f44-4f03-8474-ff0a7926a543\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610764,\"participants\":[{\"id\":996951,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996952,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"4674593f-9f44-4f03-8474-ff0a7926a543\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4674593f-9f44-4f03-8474-ff0a7926a543\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4674593f-9f44-4f03-8474-ff0a7926a543\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"4674593f-9f44-4f03-8474-ff0a7926a543\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"4674593f-9f44-4f03-8474-ff0a7926a543\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"4674593f-9f44-4f03-8474-ff0a7926a543\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"4674593f-9f44-4f03-8474-ff0a7926a543\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"4674593f-9f44-4f03-8474-ff0a7926a543\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610506,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"9c459c55-c8be-453e-9540-0477f5134f6f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610506} {\"correlation_id\":\"9c459c55-c8be-453e-9540-0477f5134f6f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610506,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"9c459c55-c8be-453e-9540-0477f5134f6f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610506,\"participants\":[{\"id\":996419,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996420,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"9c459c55-c8be-453e-9540-0477f5134f6f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"9c459c55-c8be-453e-9540-0477f5134f6f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"9c459c55-c8be-453e-9540-0477f5134f6f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"9c459c55-c8be-453e-9540-0477f5134f6f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"9c459c55-c8be-453e-9540-0477f5134f6f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"9c459c55-c8be-453e-9540-0477f5134f6f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"9c459c55-c8be-453e-9540-0477f5134f6f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":10} {\"correlation_id\":\"9c459c55-c8be-453e-9540-0477f5134f6f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610403,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"52ae8415-fd35-4109-8db4-45893cf37c4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610403} {\"correlation_id\":\"52ae8415-fd35-4109-8db4-45893cf37c4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610403,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"52ae8415-fd35-4109-8db4-45893cf37c4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610403,\"participants\":[{\"id\":996282,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996283,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"52ae8415-fd35-4109-8db4-45893cf37c4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"52ae8415-fd35-4109-8db4-45893cf37c4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"52ae8415-fd35-4109-8db4-45893cf37c4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"52ae8415-fd35-4109-8db4-45893cf37c4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"52ae8415-fd35-4109-8db4-45893cf37c4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"52ae8415-fd35-4109-8db4-45893cf37c4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"52ae8415-fd35-4109-8db4-45893cf37c4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":15} {\"correlation_id\":\"52ae8415-fd35-4109-8db4-45893cf37c4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614382,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3693e67e-875d-4232-a495-1621a90bf41a\"}\n[2026-05-11 10:17:58] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614382} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3693e67e-875d-4232-a495-1621a90bf41a\"}\n[2026-05-11 10:17:58] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614382,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3693e67e-875d-4232-a495-1621a90bf41a\"}\n[2026-05-11 10:17:58] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614382,\"participants\":[{\"id\":1002632,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002633,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3693e67e-875d-4232-a495-1621a90bf41a\"}\n[2026-05-11 10:17:58] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3693e67e-875d-4232-a495-1621a90bf41a\"}\n[2026-05-11 10:17:58] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3693e67e-875d-4232-a495-1621a90bf41a\"}\n[2026-05-11 10:17:58] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3693e67e-875d-4232-a495-1621a90bf41a\"}\n[2026-05-11 10:17:58] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3693e67e-875d-4232-a495-1621a90bf41a\"}\n[2026-05-11 10:17:58] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3693e67e-875d-4232-a495-1621a90bf41a\"}\n[2026-05-11 10:17:58] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3693e67e-875d-4232-a495-1621a90bf41a\"}\n[2026-05-11 10:17:58] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614436,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"56a279f5-3276-4781-9691-6ac712992a03\"}\n[2026-05-11 10:17:58] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614436} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"56a279f5-3276-4781-9691-6ac712992a03\"}\n[2026-05-11 10:17:58] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614436,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"56a279f5-3276-4781-9691-6ac712992a03\"}\n[2026-05-11 10:17:58] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614436,\"participants\":[{\"id\":1002751,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002752,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"56a279f5-3276-4781-9691-6ac712992a03\"}\n[2026-05-11 10:17:58] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"56a279f5-3276-4781-9691-6ac712992a03\"}\n[2026-05-11 10:17:58] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"56a279f5-3276-4781-9691-6ac712992a03\"}\n[2026-05-11 10:17:58] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"56a279f5-3276-4781-9691-6ac712992a03\"}\n[2026-05-11 10:17:58] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"56a279f5-3276-4781-9691-6ac712992a03\"}\n[2026-05-11 10:17:59] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"56a279f5-3276-4781-9691-6ac712992a03\"}\n[2026-05-11 10:17:59] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"56a279f5-3276-4781-9691-6ac712992a03\"}\n[2026-05-11 10:17:59] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612562,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"2149fff4-fc50-4b5e-8346-f4fe92446383\"}\n[2026-05-11 10:17:59] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612562} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"2149fff4-fc50-4b5e-8346-f4fe92446383\"}\n[2026-05-11 10:17:59] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612562,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"2149fff4-fc50-4b5e-8346-f4fe92446383\"}\n[2026-05-11 10:17:59] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612562,\"participants\":[{\"id\":999782,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999783,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"2149fff4-fc50-4b5e-8346-f4fe92446383\"}\n[2026-05-11 10:17:59] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"2149fff4-fc50-4b5e-8346-f4fe92446383\"}\n[2026-05-11 10:17:59] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"2149fff4-fc50-4b5e-8346-f4fe92446383\"}\n[2026-05-11 10:17:59] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"2149fff4-fc50-4b5e-8346-f4fe92446383\"}\n[2026-05-11 10:17:59] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"2149fff4-fc50-4b5e-8346-f4fe92446383\"}\n[2026-05-11 10:17:59] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"2149fff4-fc50-4b5e-8346-f4fe92446383\"}\n[2026-05-11 10:17:59] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"2149fff4-fc50-4b5e-8346-f4fe92446383\"}\n[2026-05-11 10:17:59] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610438,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"6c488719-2433-44c2-be14-6234030389cb\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:59] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610438} {\"correlation_id\":\"6c488719-2433-44c2-be14-6234030389cb\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:59] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610438,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"6c488719-2433-44c2-be14-6234030389cb\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:59] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610438,\"participants\":[{\"id\":996320,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996321,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"6c488719-2433-44c2-be14-6234030389cb\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:59] local.INFO: [ EsUpdateProcessManager ] Finished updating entities in ES {\"worker\":\"\",\"peak_memory\":\"99.73 MB\",\"elapsed_seconds\":0.31,\"update_target\":\"activities\",\"should_iterate_again\":false} {\"correlation_id\":\"4ad05333-9afb-492e-9f0f-b2909ac45b32\",\"trace_id\":\"3d8feb24-b173-4158-b0a4-4cf33af85066\"}\n[2026-05-11 10:17:59] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"6c488719-2433-44c2-be14-6234030389cb\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:59] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"6c488719-2433-44c2-be14-6234030389cb\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:59] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6c488719-2433-44c2-be14-6234030389cb\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:59] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"6c488719-2433-44c2-be14-6234030389cb\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:59] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"6c488719-2433-44c2-be14-6234030389cb\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:59] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"6c488719-2433-44c2-be14-6234030389cb\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:59] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":13} {\"correlation_id\":\"6c488719-2433-44c2-be14-6234030389cb\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:00] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612819,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"af37fbba-e927-4df9-840b-3ede48a1d911\"}\n[2026-05-11 10:18:00] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612819} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"af37fbba-e927-4df9-840b-3ede48a1d911\"}\n[2026-05-11 10:18:00] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612819,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"af37fbba-e927-4df9-840b-3ede48a1d911\"}\n[2026-05-11 10:18:00] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612819,\"participants\":[{\"id\":1000073,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1000074,\"user_id\":261,\"contact_id\":null,\"lead_id\":null},{\"id\":1000075,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"af37fbba-e927-4df9-840b-3ede48a1d911\"}\n[2026-05-11 10:18:00] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"af37fbba-e927-4df9-840b-3ede48a1d911\"}\n[2026-05-11 10:18:00] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"af37fbba-e927-4df9-840b-3ede48a1d911\"}\n[2026-05-11 10:18:00] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"af37fbba-e927-4df9-840b-3ede48a1d911\"}\n[2026-05-11 10:18:00] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"af37fbba-e927-4df9-840b-3ede48a1d911\"}\n[2026-05-11 10:18:00] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"af37fbba-e927-4df9-840b-3ede48a1d911\"}\n[2026-05-11 10:18:00] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612819,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"af37fbba-e927-4df9-840b-3ede48a1d911\"}\n[2026-05-11 10:18:00] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"af37fbba-e927-4df9-840b-3ede48a1d911\"}\n[2026-05-11 10:18:00] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"af37fbba-e927-4df9-840b-3ede48a1d911\"}\n[2026-05-11 10:18:00] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612847,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"534825cf-e6d0-42f8-8ff6-18fee9ebbcf9\"}\n[2026-05-11 10:18:00] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612847} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"534825cf-e6d0-42f8-8ff6-18fee9ebbcf9\"}\n[2026-05-11 10:18:00] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612847,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"534825cf-e6d0-42f8-8ff6-18fee9ebbcf9\"}\n[2026-05-11 10:18:00] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612847,\"participants\":[{\"id\":1000130,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1000131,\"user_id\":261,\"contact_id\":null,\"lead_id\":null},{\"id\":1000151,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"534825cf-e6d0-42f8-8ff6-18fee9ebbcf9\"}\n[2026-05-11 10:18:00] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"534825cf-e6d0-42f8-8ff6-18fee9ebbcf9\"}\n[2026-05-11 10:18:00] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"534825cf-e6d0-42f8-8ff6-18fee9ebbcf9\"}\n[2026-05-11 10:18:00] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"534825cf-e6d0-42f8-8ff6-18fee9ebbcf9\"}\n[2026-05-11 10:18:00] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"534825cf-e6d0-42f8-8ff6-18fee9ebbcf9\"}\n[2026-05-11 10:18:00] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"534825cf-e6d0-42f8-8ff6-18fee9ebbcf9\"}\n[2026-05-11 10:18:00] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"534825cf-e6d0-42f8-8ff6-18fee9ebbcf9\"}\n[2026-05-11 10:18:00] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610470,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"13c3f8a7-53c0-490e-915d-f30216c6fae9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:00] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610470} {\"correlation_id\":\"13c3f8a7-53c0-490e-915d-f30216c6fae9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:00] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610470,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"13c3f8a7-53c0-490e-915d-f30216c6fae9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:00] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610470,\"participants\":[{\"id\":996369,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996370,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"13c3f8a7-53c0-490e-915d-f30216c6fae9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:00] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"13c3f8a7-53c0-490e-915d-f30216c6fae9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:00] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"13c3f8a7-53c0-490e-915d-f30216c6fae9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:00] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"13c3f8a7-53c0-490e-915d-f30216c6fae9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:00] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"13c3f8a7-53c0-490e-915d-f30216c6fae9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:00] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"13c3f8a7-53c0-490e-915d-f30216c6fae9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:00] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"13c3f8a7-53c0-490e-915d-f30216c6fae9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:00] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":15} {\"correlation_id\":\"13c3f8a7-53c0-490e-915d-f30216c6fae9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610900,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"785d023d-231c-4c69-9e14-64b9f386cd8a\"}\n[2026-05-11 10:18:01] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610900} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"785d023d-231c-4c69-9e14-64b9f386cd8a\"}\n[2026-05-11 10:18:01] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610900,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"785d023d-231c-4c69-9e14-64b9f386cd8a\"}\n[2026-05-11 10:18:01] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610900,\"participants\":[{\"id\":997081,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997082,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"785d023d-231c-4c69-9e14-64b9f386cd8a\"}\n[2026-05-11 10:18:01] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"785d023d-231c-4c69-9e14-64b9f386cd8a\"}\n[2026-05-11 10:18:01] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"785d023d-231c-4c69-9e14-64b9f386cd8a\"}\n[2026-05-11 10:18:01] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"785d023d-231c-4c69-9e14-64b9f386cd8a\"}\n[2026-05-11 10:18:01] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"785d023d-231c-4c69-9e14-64b9f386cd8a\"}\n[2026-05-11 10:18:01] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"785d023d-231c-4c69-9e14-64b9f386cd8a\"}\n[2026-05-11 10:18:01] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"785d023d-231c-4c69-9e14-64b9f386cd8a\"}\n[2026-05-11 10:18:01] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610426,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"aea37783-669f-433b-aac7-ead252f60285\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610426} {\"correlation_id\":\"aea37783-669f-433b-aac7-ead252f60285\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610426,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"aea37783-669f-433b-aac7-ead252f60285\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610426,\"participants\":[{\"id\":996306,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996307,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"aea37783-669f-433b-aac7-ead252f60285\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"aea37783-669f-433b-aac7-ead252f60285\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"aea37783-669f-433b-aac7-ead252f60285\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"aea37783-669f-433b-aac7-ead252f60285\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"aea37783-669f-433b-aac7-ead252f60285\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"aea37783-669f-433b-aac7-ead252f60285\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"aea37783-669f-433b-aac7-ead252f60285\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":10} {\"correlation_id\":\"aea37783-669f-433b-aac7-ead252f60285\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610935,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73386989-234b-4074-93cd-b907d73fb039\"}\n[2026-05-11 10:18:01] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610935} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73386989-234b-4074-93cd-b907d73fb039\"}\n[2026-05-11 10:18:01] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610935,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73386989-234b-4074-93cd-b907d73fb039\"}\n[2026-05-11 10:18:01] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610935,\"participants\":[{\"id\":997141,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997142,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73386989-234b-4074-93cd-b907d73fb039\"}\n[2026-05-11 10:18:01] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73386989-234b-4074-93cd-b907d73fb039\"}\n[2026-05-11 10:18:01] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73386989-234b-4074-93cd-b907d73fb039\"}\n[2026-05-11 10:18:01] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73386989-234b-4074-93cd-b907d73fb039\"}\n[2026-05-11 10:18:01] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73386989-234b-4074-93cd-b907d73fb039\"}\n[2026-05-11 10:18:01] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73386989-234b-4074-93cd-b907d73fb039\"}\n[2026-05-11 10:18:01] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73386989-234b-4074-93cd-b907d73fb039\"}\n[2026-05-11 10:18:01] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612560,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"67837137-7da9-4fc3-807c-fa87dbcc5090\"}\n[2026-05-11 10:18:01] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612560} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"67837137-7da9-4fc3-807c-fa87dbcc5090\"}\n[2026-05-11 10:18:01] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612560,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"67837137-7da9-4fc3-807c-fa87dbcc5090\"}\n[2026-05-11 10:18:01] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612560,\"participants\":[{\"id\":999778,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999779,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"67837137-7da9-4fc3-807c-fa87dbcc5090\"}\n[2026-05-11 10:18:01] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"67837137-7da9-4fc3-807c-fa87dbcc5090\"}\n[2026-05-11 10:18:01] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"67837137-7da9-4fc3-807c-fa87dbcc5090\"}\n[2026-05-11 10:18:01] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"67837137-7da9-4fc3-807c-fa87dbcc5090\"}\n[2026-05-11 10:18:01] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"67837137-7da9-4fc3-807c-fa87dbcc5090\"}\n[2026-05-11 10:18:01] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"67837137-7da9-4fc3-807c-fa87dbcc5090\"}\n[2026-05-11 10:18:01] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"67837137-7da9-4fc3-807c-fa87dbcc5090\"}\n[2026-05-11 10:18:01] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612561,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1d0c22f1-5e71-452c-94ab-4a7ba39ee8be\"}\n[2026-05-11 10:18:01] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612561} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1d0c22f1-5e71-452c-94ab-4a7ba39ee8be\"}\n[2026-05-11 10:18:01] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612561,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1d0c22f1-5e71-452c-94ab-4a7ba39ee8be\"}\n[2026-05-11 10:18:01] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612561,\"participants\":[{\"id\":999780,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999781,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1d0c22f1-5e71-452c-94ab-4a7ba39ee8be\"}\n[2026-05-11 10:18:01] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1d0c22f1-5e71-452c-94ab-4a7ba39ee8be\"}\n[2026-05-11 10:18:01] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1d0c22f1-5e71-452c-94ab-4a7ba39ee8be\"}\n[2026-05-11 10:18:01] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1d0c22f1-5e71-452c-94ab-4a7ba39ee8be\"}\n[2026-05-11 10:18:01] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1d0c22f1-5e71-452c-94ab-4a7ba39ee8be\"}\n[2026-05-11 10:18:01] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612561,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1d0c22f1-5e71-452c-94ab-4a7ba39ee8be\"}\n[2026-05-11 10:18:01] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"447700174614.447782589921.OeREojLVnk@txt.staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1d0c22f1-5e71-452c-94ab-4a7ba39ee8be\"}\n[2026-05-11 10:18:01] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"447700174614.447782589921.OeREojLVnk@txt.staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1d0c22f1-5e71-452c-94ab-4a7ba39ee8be\"}\n[2026-05-11 10:18:01] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610462,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"5e4163ac-fdc7-49df-89de-383bf3f5bcd4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610462} {\"correlation_id\":\"5e4163ac-fdc7-49df-89de-383bf3f5bcd4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610462,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"5e4163ac-fdc7-49df-89de-383bf3f5bcd4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610462,\"participants\":[{\"id\":996353,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996354,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"5e4163ac-fdc7-49df-89de-383bf3f5bcd4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"5e4163ac-fdc7-49df-89de-383bf3f5bcd4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"5e4163ac-fdc7-49df-89de-383bf3f5bcd4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"5e4163ac-fdc7-49df-89de-383bf3f5bcd4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"5e4163ac-fdc7-49df-89de-383bf3f5bcd4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"5e4163ac-fdc7-49df-89de-383bf3f5bcd4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"5e4163ac-fdc7-49df-89de-383bf3f5bcd4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":10} {\"correlation_id\":\"5e4163ac-fdc7-49df-89de-383bf3f5bcd4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:02] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614378,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":6167,\"account_id\":null,\"opportunity_id\":null,\"stage_id\":null}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9476099f-6f93-4402-b763-b075c4f8ed44\"}\n[2026-05-11 10:18:02] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614378} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9476099f-6f93-4402-b763-b075c4f8ed44\"}\n[2026-05-11 10:18:02] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614378,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9476099f-6f93-4402-b763-b075c4f8ed44\"}\n[2026-05-11 10:18:02] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614378,\"participants\":[{\"id\":1002623,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002624,\"user_id\":null,\"contact_id\":6167,\"lead_id\":null},{\"id\":1002625,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9476099f-6f93-4402-b763-b075c4f8ed44\"}\n[2026-05-11 10:18:02] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9476099f-6f93-4402-b763-b075c4f8ed44\"}\n[2026-05-11 10:18:02] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9476099f-6f93-4402-b763-b075c4f8ed44\"}\n[2026-05-11 10:18:02] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9476099f-6f93-4402-b763-b075c4f8ed44\"}\n[2026-05-11 10:18:02] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9476099f-6f93-4402-b763-b075c4f8ed44\"}\n[2026-05-11 10:18:02] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9476099f-6f93-4402-b763-b075c4f8ed44\"}\n[2026-05-11 10:18:02] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9476099f-6f93-4402-b763-b075c4f8ed44\"}\n[2026-05-11 10:18:03] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":615092,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7e0e12d1-b270-490b-848b-763e373c90e0\"}\n[2026-05-11 10:18:03] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":615092} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7e0e12d1-b270-490b-848b-763e373c90e0\"}\n[2026-05-11 10:18:03] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":615092,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7e0e12d1-b270-490b-848b-763e373c90e0\"}\n[2026-05-11 10:18:03] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":615092,\"participants\":[{\"id\":1004102,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1004103,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7e0e12d1-b270-490b-848b-763e373c90e0\"}\n[2026-05-11 10:18:03] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7e0e12d1-b270-490b-848b-763e373c90e0\"}\n[2026-05-11 10:18:03] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7e0e12d1-b270-490b-848b-763e373c90e0\"}\n[2026-05-11 10:18:03] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7e0e12d1-b270-490b-848b-763e373c90e0\"}\n[2026-05-11 10:18:03] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7e0e12d1-b270-490b-848b-763e373c90e0\"}\n[2026-05-11 10:18:03] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7e0e12d1-b270-490b-848b-763e373c90e0\"}\n[2026-05-11 10:18:03] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7e0e12d1-b270-490b-848b-763e373c90e0\"}\n[2026-05-11 10:18:03] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611451,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"adaf1f1e-8477-469f-86c9-9c59d2623f11\"}\n[2026-05-11 10:18:03] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611451} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"adaf1f1e-8477-469f-86c9-9c59d2623f11\"}\n[2026-05-11 10:18:03] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611451,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"adaf1f1e-8477-469f-86c9-9c59d2623f11\"}\n[2026-05-11 10:18:03] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611451,\"participants\":[{\"id\":997955,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997956,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"adaf1f1e-8477-469f-86c9-9c59d2623f11\"}\n[2026-05-11 10:18:03] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"adaf1f1e-8477-469f-86c9-9c59d2623f11\"}\n[2026-05-11 10:18:03] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"adaf1f1e-8477-469f-86c9-9c59d2623f11\"}\n[2026-05-11 10:18:03] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"adaf1f1e-8477-469f-86c9-9c59d2623f11\"}\n[2026-05-11 10:18:03] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"adaf1f1e-8477-469f-86c9-9c59d2623f11\"}\n[2026-05-11 10:18:03] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"adaf1f1e-8477-469f-86c9-9c59d2623f11\"}\n[2026-05-11 10:18:03] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"adaf1f1e-8477-469f-86c9-9c59d2623f11\"}\n[2026-05-11 10:18:03] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612336,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1235043b-578e-49e0-9ebe-230be6d9a8f8\"}\n[2026-05-11 10:18:03] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612336} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1235043b-578e-49e0-9ebe-230be6d9a8f8\"}\n[2026-05-11 10:18:03] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612336,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1235043b-578e-49e0-9ebe-230be6d9a8f8\"}\n[2026-05-11 10:18:03] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612336,\"participants\":[{\"id\":999508,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999509,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999512,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999513,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1235043b-578e-49e0-9ebe-230be6d9a8f8\"}\n[2026-05-11 10:18:03] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1235043b-578e-49e0-9ebe-230be6d9a8f8\"}\n[2026-05-11 10:18:03] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1235043b-578e-49e0-9ebe-230be6d9a8f8\"}\n[2026-05-11 10:18:03] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1235043b-578e-49e0-9ebe-230be6d9a8f8\"}\n[2026-05-11 10:18:03] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1235043b-578e-49e0-9ebe-230be6d9a8f8\"}\n[2026-05-11 10:18:03] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1235043b-578e-49e0-9ebe-230be6d9a8f8\"}\n[2026-05-11 10:18:03] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612336,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1235043b-578e-49e0-9ebe-230be6d9a8f8\"}\n[2026-05-11 10:18:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610539,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610539} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610539,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:04] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610539,\"participants\":[{\"id\":996485,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996486,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:04] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:04] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:04] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:04] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:04] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:04] local.INFO: [ EsUpdateProcessManager ] Finished updating entities in ES {\"worker\":\"\",\"peak_memory\":\"99.73 MB\",\"elapsed_seconds\":0.47,\"update_target\":\"activities\",\"should_iterate_again\":false} {\"correlation_id\":\"4ad05333-9afb-492e-9f0f-b2909ac45b32\",\"trace_id\":\"3d8feb24-b173-4158-b0a4-4cf33af85066\"}\n[2026-05-11 10:18:04] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/contact/search\",\"total_requests\":1,\"total_records_fetched\":0,\"total_elapsed_seconds\":0.3,\"average_seconds_per_request\":0.3} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:05] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:05] local.INFO: [Prospect match] Cache miss {\"identifier_type\":\"domain\",\"identifier\":\"jiminny.com\",\"crm\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:05] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"domain\",\"identifier\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:05] local.INFO: [HubSpot] importAccount {\"crm_provider_id\":\"749766179\",\"config_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:05] local.INFO: [HubSpot] CRM Search requested {\"request\":{\"filterGroups\":[{\"filters\":[{\"propertyName\":\"associations.company\",\"operator\":\"EQ\",\"value\":\"749766179\"},{\"propertyName\":\"dealstage\",\"operator\":\"NOT_IN\",\"values\":[\"closedwon\",\"4040964\",\"59247967\"]},{\"propertyName\":\"dealstage\",\"operator\":\"NOT_IN\",\"values\":[\"closedlost\",\"4040965\",\"59247968\"]}]}],\"sorts\":[{\"propertyName\":\"modifieddate\",\"direction\":\"DESCENDING\"}],\"properties\":[\"dealname\",\"amount\",\"hubspot_owner_id\",\"pipeline\",\"dealstage\",\"closedate\",\"deal_currency_code\"],\"limit\":200}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:05] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/deals/search\",\"total_requests\":1,\"total_records_fetched\":10,\"total_elapsed_seconds\":0.24,\"average_seconds_per_request\":0.24} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"1042ef38-481f-4e55-9261-bb89ceb4cd6f\",\"trace_id\":\"3cbbfc20-36d7-4827-9e77-e5ea12d34c82\"}\n[2026-05-11 10:18:06] local.INFO: [ScheduleBotCommand] Number of activities to be captured: 0 {\"correlation_id\":\"1042ef38-481f-4e55-9261-bb89ceb4cd6f\",\"trace_id\":\"3cbbfc20-36d7-4827-9e77-e5ea12d34c82\"}\n[2026-05-11 10:18:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"1042ef38-481f-4e55-9261-bb89ceb4cd6f\",\"trace_id\":\"3cbbfc20-36d7-4827-9e77-e5ea12d34c82\"}\n[2026-05-11 10:18:06] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610539,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:06] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610539,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610539} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610539,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:06] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610539,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:06] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610878,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610878} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610878,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:06] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610878,\"participants\":[{\"id\":997035,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997036,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:06] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:06] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:06] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:06] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:06] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:06] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:06] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:06] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610878,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:07] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610878,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610878} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610878,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:07] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610878,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:07] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612340,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612340} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612340,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:07] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612340,\"participants\":[{\"id\":999516,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999517,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999518,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999519,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:07] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:07] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:07] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:07] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:07] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:07] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612340,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:07] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/contact/search\",\"total_requests\":1,\"total_records_fetched\":0,\"total_elapsed_seconds\":0.25,\"average_seconds_per_request\":0.25} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:07] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/contact/search\",\"total_requests\":1,\"total_records_fetched\":0,\"total_elapsed_seconds\":0.48,\"average_seconds_per_request\":0.48} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:07] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612340,\"participants_processed\":4,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612340} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612340,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:07] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612340,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:08] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612360,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bea3a6fc-5389-4a59-a601-2f8fe9a2d01c\"}\n[2026-05-11 10:18:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612360} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bea3a6fc-5389-4a59-a601-2f8fe9a2d01c\"}\n[2026-05-11 10:18:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612360,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bea3a6fc-5389-4a59-a601-2f8fe9a2d01c\"}\n[2026-05-11 10:18:08] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612360,\"participants\":[{\"id\":999552,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999553,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999565,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bea3a6fc-5389-4a59-a601-2f8fe9a2d01c\"}\n[2026-05-11 10:18:08] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bea3a6fc-5389-4a59-a601-2f8fe9a2d01c\"}\n[2026-05-11 10:18:08] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bea3a6fc-5389-4a59-a601-2f8fe9a2d01c\"}\n[2026-05-11 10:18:08] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bea3a6fc-5389-4a59-a601-2f8fe9a2d01c\"}\n[2026-05-11 10:18:08] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bea3a6fc-5389-4a59-a601-2f8fe9a2d01c\"}\n[2026-05-11 10:18:08] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bea3a6fc-5389-4a59-a601-2f8fe9a2d01c\"}\n[2026-05-11 10:18:08] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612360,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bea3a6fc-5389-4a59-a601-2f8fe9a2d01c\"}\n[2026-05-11 10:18:08] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612360,\"participants_processed\":3,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bea3a6fc-5389-4a59-a601-2f8fe9a2d01c\"}\n[2026-05-11 10:18:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612360} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bea3a6fc-5389-4a59-a601-2f8fe9a2d01c\"}\n[2026-05-11 10:18:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612360,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bea3a6fc-5389-4a59-a601-2f8fe9a2d01c\"}\n[2026-05-11 10:18:08] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612360,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bea3a6fc-5389-4a59-a601-2f8fe9a2d01c\"}\n[2026-05-11 10:18:08] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612339,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f92f5ee2-fe1d-48c0-812c-1ef5822e650b\"}\n[2026-05-11 10:18:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612339} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f92f5ee2-fe1d-48c0-812c-1ef5822e650b\"}\n[2026-05-11 10:18:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612339,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f92f5ee2-fe1d-48c0-812c-1ef5822e650b\"}\n[2026-05-11 10:18:08] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612339,\"participants\":[{\"id\":999514,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999515,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999540,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f92f5ee2-fe1d-48c0-812c-1ef5822e650b\"}\n[2026-05-11 10:18:08] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f92f5ee2-fe1d-48c0-812c-1ef5822e650b\"}\n[2026-05-11 10:18:08] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f92f5ee2-fe1d-48c0-812c-1ef5822e650b\"}\n[2026-05-11 10:18:08] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f92f5ee2-fe1d-48c0-812c-1ef5822e650b\"}\n[2026-05-11 10:18:08] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f92f5ee2-fe1d-48c0-812c-1ef5822e650b\"}\n[2026-05-11 10:18:08] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f92f5ee2-fe1d-48c0-812c-1ef5822e650b\"}\n[2026-05-11 10:18:08] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612339,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f92f5ee2-fe1d-48c0-812c-1ef5822e650b\"}\n[2026-05-11 10:18:08] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612339,\"participants_processed\":3,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f92f5ee2-fe1d-48c0-812c-1ef5822e650b\"}\n[2026-05-11 10:18:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612339} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f92f5ee2-fe1d-48c0-812c-1ef5822e650b\"}\n[2026-05-11 10:18:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612339,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f92f5ee2-fe1d-48c0-812c-1ef5822e650b\"}\n[2026-05-11 10:18:08] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612339,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f92f5ee2-fe1d-48c0-812c-1ef5822e650b\"}\n[2026-05-11 10:18:08] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611455,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611455} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611455,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:08] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611455,\"participants\":[{\"id\":997961,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997962,\"user_id\":1460,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:08] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:08] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:08] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:08] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:08] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:08] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"support@staging.jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/support%40staging.jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:08] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:09] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/contact/search\",\"total_requests\":1,\"total_records_fetched\":0,\"total_elapsed_seconds\":0.66,\"average_seconds_per_request\":0.66} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:09] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:09] local.INFO: [Prospect match] Cache miss {\"identifier_type\":\"domain\",\"identifier\":\"jiminny.com\",\"crm\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:09] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"domain\",\"identifier\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:09] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"e0173b67-adc7-4861-acea-33ec563fa8bc\",\"trace_id\":\"df5cbecf-dde1-4674-82c8-8b7a2f4b74de\"}\n[2026-05-11 10:18:09] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"e0173b67-adc7-4861-acea-33ec563fa8bc\",\"trace_id\":\"df5cbecf-dde1-4674-82c8-8b7a2f4b74de\"}\n[2026-05-11 10:18:09] local.INFO: [HubSpot] importAccount {\"crm_provider_id\":\"749766179\",\"config_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:09] local.INFO: [HubSpot] CRM Search requested {\"request\":{\"filterGroups\":[{\"filters\":[{\"propertyName\":\"associations.company\",\"operator\":\"EQ\",\"value\":\"749766179\"},{\"propertyName\":\"dealstage\",\"operator\":\"NOT_IN\",\"values\":[\"closedwon\",\"4040964\",\"59247967\"]},{\"propertyName\":\"dealstage\",\"operator\":\"NOT_IN\",\"values\":[\"closedlost\",\"4040965\",\"59247968\"]}]}],\"sorts\":[{\"propertyName\":\"modifieddate\",\"direction\":\"DESCENDING\"}],\"properties\":[\"dealname\",\"amount\",\"hubspot_owner_id\",\"pipeline\",\"dealstage\",\"closedate\",\"deal_currency_code\"],\"limit\":200}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:09] local.INFO: [ EsUpdateProcessManager ] Finished updating entities in ES {\"worker\":\"\",\"peak_memory\":\"99.73 MB\",\"elapsed_seconds\":0.3,\"update_target\":\"activities\",\"should_iterate_again\":false} {\"correlation_id\":\"4ad05333-9afb-492e-9f0f-b2909ac45b32\",\"trace_id\":\"3d8feb24-b173-4158-b0a4-4cf33af85066\"}\n[2026-05-11 10:18:09] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/deals/search\",\"total_requests\":1,\"total_records_fetched\":10,\"total_elapsed_seconds\":0.26,\"average_seconds_per_request\":0.26} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":611455,\"team_id\":2,\"email\":\"aneliya.angelova@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":611455,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611455} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611455,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":611455,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610915,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610915} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610915,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610915,\"participants\":[{\"id\":997104,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997105,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610915,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610915,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610915} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610915,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610915,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610528,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610528} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610528,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610528,\"participants\":[{\"id\":996463,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996464,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610528,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610528,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610528} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610528,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610528,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611087,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611087} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611087,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611087,\"participants\":[{\"id\":997368,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997369,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":611087,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":611087,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611087} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611087,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":611087,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611076,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611076} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611076,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611076,\"participants\":[{\"id\":997346,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997347,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":611076,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":611076,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611076} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611076,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":611076,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610497,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610497} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610497,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610497,\"participants\":[{\"id\":996401,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996402,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610497,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610497,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610497} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610497,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610497,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610867,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610867} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610867,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610867,\"participants\":[{\"id\":997011,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997012,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610867,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610867,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610867} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610867,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610867,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610490,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610490} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610490,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610490,\"participants\":[{\"id\":996385,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996386,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610490,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610490,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610490} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610490,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610490,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610506,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610506} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610506,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610506,\"participants\":[{\"id\":996419,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996420,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610506,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610506,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610506} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610506,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610506,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610885,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610885} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610885,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:11] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610885,\"participants\":[{\"id\":997051,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997052,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:11] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:11] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:11] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:11] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:11] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:11] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:11] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:11] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610885,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:11] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610885,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:11] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610885} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:11] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610885,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:11] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610885,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:11] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610874,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610874} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610874,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610874,\"participants\":[{\"id\":997025,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997026,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610874,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610874,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610874} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610874,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610874,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610617,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610617} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610617,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610617,\"participants\":[{\"id\":996641,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996642,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610617,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610617,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610617} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610617,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610617,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614382,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:11] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614382} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:11] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614382,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:11] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614382,\"participants\":[{\"id\":1002632,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002633,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:11] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:11] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:11] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:11] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:11] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:11] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"nikolay.nikolov@jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/nikolay.nikolov%40jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:11] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:11] local.NOTICE: Monitoring start {\"correlation_id\":\"f1c8fc03-337f-4edb-a859-cd9fb18b900e\",\"trace_id\":\"503eff58-a255-4b63-9001-481d9a9bd530\"}\n[2026-05-11 10:18:11] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/contact/search\",\"total_requests\":1,\"total_records_fetched\":0,\"total_elapsed_seconds\":0.27,\"average_seconds_per_request\":0.27} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:11] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"nikolay.nikolov@jiminny.com\",\"domain\":\"jiminny.com\"} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:11] local.INFO: [Prospect match] Cache miss {\"identifier_type\":\"domain\",\"identifier\":\"jiminny.com\",\"crm\":\"hubspot\"} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:11] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"domain\",\"identifier\":\"jiminny.com\"} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:11] local.NOTICE: Monitoring end {\"correlation_id\":\"f1c8fc03-337f-4edb-a859-cd9fb18b900e\",\"trace_id\":\"503eff58-a255-4b63-9001-481d9a9bd530\"}\n[2026-05-11 10:18:12] local.INFO: [HubSpot] importAccount {\"crm_provider_id\":\"749766179\",\"config_id\":2} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:12] local.INFO: [HubSpot] CRM Search requested {\"request\":{\"filterGroups\":[{\"filters\":[{\"propertyName\":\"associations.company\",\"operator\":\"EQ\",\"value\":\"749766179\"},{\"propertyName\":\"dealstage\",\"operator\":\"NOT_IN\",\"values\":[\"closedwon\",\"4040964\",\"59247967\"]},{\"propertyName\":\"dealstage\",\"operator\":\"NOT_IN\",\"values\":[\"closedlost\",\"4040965\",\"59247968\"]}]}],\"sorts\":[{\"propertyName\":\"modifieddate\",\"direction\":\"DESCENDING\"}],\"properties\":[\"dealname\",\"amount\",\"hubspot_owner_id\",\"pipeline\",\"dealstage\",\"closedate\",\"deal_currency_code\"],\"limit\":200}} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:12] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/deals/search\",\"total_requests\":1,\"total_records_fetched\":10,\"total_elapsed_seconds\":0.42,\"average_seconds_per_request\":0.42} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:14] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":614382,\"team_id\":2,\"email\":\"nikolay.nikolov@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:14] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":614382,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:14] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614382} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:14] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614382,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":614382,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614381,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614381} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614381,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614381,\"participants\":[{\"id\":1002630,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002631,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"nikolay.nikolov@jiminny.com\",\"domain\":\"jiminny.com\"} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":614381,\"team_id\":2,\"email\":\"nikolay.nikolov@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":614381,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614381} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614381,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":614381,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [ EsUpdateProcessManager ] Finished updating entities in ES {\"worker\":\"\",\"peak_memory\":\"99.73 MB\",\"elapsed_seconds\":0.55,\"update_target\":\"activities\",\"should_iterate_again\":false} {\"correlation_id\":\"4ad05333-9afb-492e-9f0f-b2909ac45b32\",\"trace_id\":\"3d8feb24-b173-4158-b0a4-4cf33af85066\"}\n[2026-05-11 10:18:15] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610426,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:15] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610426} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:15] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610426,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:15] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610426,\"participants\":[{\"id\":996306,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996307,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:15] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:15] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:15] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:15] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:15] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:15] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:15] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:15] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610426,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:15] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610426,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:15] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610426} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:15] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610426,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:15] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610426,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:16] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612560,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:16] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612560} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:16] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612560,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:16] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612560,\"participants\":[{\"id\":999778,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999779,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:16] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:16] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:16] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:16] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:16] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:16] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"447782589921@txt.staging.jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/447782589921%40txt.staging.jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:16] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:16] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/contact/search\",\"total_requests\":1,\"total_records_fetched\":0,\"total_elapsed_seconds\":0.27,\"average_seconds_per_request\":0.27} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:16] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"447782589921@txt.staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:16] local.INFO: [Prospect match] Cache miss {\"identifier_type\":\"domain\",\"identifier\":\"jiminny.com\",\"crm\":\"hubspot\"} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:16] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"domain\",\"identifier\":\"jiminny.com\"} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:17] local.INFO: [HubSpot] importAccount {\"crm_provider_id\":\"749766179\",\"config_id\":2} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:17] local.INFO: [HubSpot] CRM Search requested {\"request\":{\"filterGroups\":[{\"filters\":[{\"propertyName\":\"associations.company\",\"operator\":\"EQ\",\"value\":\"749766179\"},{\"propertyName\":\"dealstage\",\"operator\":\"NOT_IN\",\"values\":[\"closedwon\",\"4040964\",\"59247967\"]},{\"propertyName\":\"dealstage\",\"operator\":\"NOT_IN\",\"values\":[\"closedlost\",\"4040965\",\"59247968\"]}]}],\"sorts\":[{\"propertyName\":\"modifieddate\",\"direction\":\"DESCENDING\"}],\"properties\":[\"dealname\",\"amount\",\"hubspot_owner_id\",\"pipeline\",\"dealstage\",\"closedate\",\"deal_currency_code\"],\"limit\":200}} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:17] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/deals/search\",\"total_requests\":1,\"total_records_fetched\":10,\"total_elapsed_seconds\":0.23,\"average_seconds_per_request\":0.23} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"4f01fa5e-5837-4b03-af04-ccad937f80f4\",\"trace_id\":\"7ea236cf-a366-4cea-8e77-3417ec22eac5\"}\n[2026-05-11 10:18:18] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"4f01fa5e-5837-4b03-af04-ccad937f80f4\",\"trace_id\":\"7ea236cf-a366-4cea-8e77-3417ec22eac5\"}\n[2026-05-11 10:18:18] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612560,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612560,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612560} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612560,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612560,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610462,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610462} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610462,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610462,\"participants\":[{\"id\":996353,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996354,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610462,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610462,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610462} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610462,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610462,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612819,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612819} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612819,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612819,\"participants\":[{\"id\":1000073,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1000074,\"user_id\":261,\"contact_id\":null,\"lead_id\":null},{\"id\":1000075,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: ProspectCache - Searching DB for opportunity by owner {\"account_id\":244,\"contact_id\":4487,\"owner_id\":261} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: ProspectCache - Opportunity DB search results {\"account_id\":244,\"contact_id\":4487,\"opportunity_id\":299} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612819,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"adelina.petrova@jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/adelina.petrova%40jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/contact/search\",\"total_requests\":1,\"total_records_fetched\":0,\"total_elapsed_seconds\":0.24,\"average_seconds_per_request\":0.24} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"adelina.petrova@jiminny.com\",\"domain\":\"jiminny.com\"} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [Prospect match] Cache miss {\"identifier_type\":\"domain\",\"identifier\":\"jiminny.com\",\"crm\":\"hubspot\"} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"domain\",\"identifier\":\"jiminny.com\"} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:19] local.INFO: [HubSpot] importAccount {\"crm_provider_id\":\"749766179\",\"config_id\":2} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:19] local.INFO: [HubSpot] CRM Search requested {\"request\":{\"filterGroups\":[{\"filters\":[{\"propertyName\":\"associations.company\",\"operator\":\"EQ\",\"value\":\"749766179\"},{\"propertyName\":\"dealstage\",\"operator\":\"NOT_IN\",\"values\":[\"closedwon\",\"4040964\",\"59247967\"]},{\"propertyName\":\"dealstage\",\"operator\":\"NOT_IN\",\"values\":[\"closedlost\",\"4040965\",\"59247968\"]}]}],\"sorts\":[{\"propertyName\":\"modifieddate\",\"direction\":\"DESCENDING\"}],\"properties\":[\"dealname\",\"amount\",\"hubspot_owner_id\",\"pipeline\",\"dealstage\",\"closedate\",\"deal_currency_code\"],\"limit\":200}} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:19] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/deals/search\",\"total_requests\":1,\"total_records_fetched\":10,\"total_elapsed_seconds\":0.23,\"average_seconds_per_request\":0.23} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:19] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"add7477b-8e9d-44ef-9c16-cf763d7fd973\",\"trace_id\":\"0a4036d4-4c6b-4724-8efb-d8375a7dfe6a\"}\n[2026-05-11 10:18:19] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"add7477b-8e9d-44ef-9c16-cf763d7fd973\",\"trace_id\":\"0a4036d4-4c6b-4724-8efb-d8375a7dfe6a\"}\n[2026-05-11 10:18:19] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"add7477b-8e9d-44ef-9c16-cf763d7fd973\",\"trace_id\":\"0a4036d4-4c6b-4724-8efb-d8375a7dfe6a\"}\n[2026-05-11 10:18:19] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"add7477b-8e9d-44ef-9c16-cf763d7fd973\",\"trace_id\":\"0a4036d4-4c6b-4724-8efb-d8375a7dfe6a\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612819,\"participants_processed\":3,\"exact_matches\":1,\"domain_matches\":1,\"best_match_found\":true} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612819} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612819,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612819,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612847,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612847} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612847,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612847,\"participants\":[{\"id\":1000130,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1000131,\"user_id\":261,\"contact_id\":null,\"lead_id\":null},{\"id\":1000151,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null}]} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"adelina.petrova@jiminny.com\",\"domain\":\"jiminny.com\"} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612847,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612847,\"participants_processed\":3,\"exact_matches\":1,\"domain_matches\":1,\"best_match_found\":true} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612847} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612847,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612847,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610451,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610451} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610451,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610451,\"participants\":[{\"id\":996340,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996341,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610451,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610451,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610451} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610451,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610451,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612562,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612562} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612562,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612562,\"participants\":[{\"id\":999782,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999783,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"447782589921@txt.staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612562,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612562,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612562} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612562,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612562,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610764,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610764} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610764,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610764,\"participants\":[{\"id\":996951,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996952,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610764,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610764,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610764} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610764,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610764,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614436,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614436} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614436,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614436,\"participants\":[{\"id\":1002751,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002752,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"nikolay.nikolov@jiminny.com\",\"domain\":\"jiminny.com\"} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":614436,\"team_id\":2,\"email\":\"nikolay.nikolov@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":614436,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614436} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614436,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":614436,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610438,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610438} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610438,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610438,\"participants\":[{\"id\":996320,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996321,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610438,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610438,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610438} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610438,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610438,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":615092,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":615092} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":615092,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":615092,\"participants\":[{\"id\":1004102,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1004103,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"nikolay.nikolov@jiminny.com\",\"domain\":\"jiminny.com\"} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":615092,\"team_id\":2,\"email\":\"nikolay.nikolov@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":615092,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":615092} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":615092,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":615092,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateProcessManager ] Finished updating entities in ES {\"worker\":\"\",\"peak_memory\":\"99.73 MB\",\"elapsed_seconds\":0.23,\"update_target\":\"activities\",\"should_iterate_again\":false} {\"correlation_id\":\"4ad05333-9afb-492e-9f0f-b2909ac45b32\",\"trace_id\":\"3d8feb24-b173-4158-b0a4-4cf33af85066\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610403,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610403} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610403,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610403,\"participants\":[{\"id\":996282,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996283,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610403,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610403,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610403} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610403,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610403,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610935,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610935} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610935,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610935,\"participants\":[{\"id\":997141,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997142,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610935,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610935,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610935} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610935,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610935,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610470,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610470} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610470,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610470,\"participants\":[{\"id\":996369,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996370,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610470,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610470,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610470} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610470,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610470,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610900,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610900} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610900,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610900,\"participants\":[{\"id\":997081,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997082,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610900,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610900,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610900} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610900,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610900,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614378,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":6167,\"account_id\":null,\"opportunity_id\":null,\"stage_id\":null}} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614378} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614378,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614378,\"participants\":[{\"id\":1002623,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002624,\"user_id\":null,\"contact_id\":6167,\"lead_id\":null},{\"id\":1002625,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"nikolay.nikolov@jiminny.com\",\"domain\":\"jiminny.com\"} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nmalchev@gmail.com\"} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":614378,\"team_id\":2,\"email\":\"nikolay.nikolov@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":614378,\"participants_processed\":3,\"exact_matches\":1,\"domain_matches\":1,\"best_match_found\":true} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614378} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614378,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":614378,\"remote_search\":true,\"lead_id\":null,\"contact_id\":6167,\"account_id\":null,\"opportunity_id\":null,\"stage_id\":null} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612561,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612561} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612561,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612561,\"participants\":[{\"id\":999780,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999781,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612561,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"447700174614.447782589921.OeREojLVnk@txt.staging.jiminny.com\"} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"447700174614.447782589921.OeREojLVnk@txt.staging.jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/447700174614.447782589921.OeREojLVnk%40txt.staging.jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"447700174614.447782589921.OeREojLVnk@txt.staging.jiminny.com\"} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"447700174614.447782589921.OeREojLVnk@txt.staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612561,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612561} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612561,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612561,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612336,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612336} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612336,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612336,\"participants\":[{\"id\":999508,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999509,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999512,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999513,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: ProspectCache - Searching DB for opportunity by owner {\"account_id\":243,\"contact_id\":4491,\"owner_id\":206} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: ProspectCache - Fallback DB opportunity search {\"account_id\":243,\"contact_id\":4491} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: ProspectCache - Opportunity DB search results {\"account_id\":243,\"contact_id\":4491,\"opportunity_id\":276} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612336,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612336,\"participants_processed\":4,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612336} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612336,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612336,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611451,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611451} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611451,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611451,\"participants\":[{\"id\":997955,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997956,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":611451,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":611451,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611451} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611451,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":611451,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"5cd332f8-5b05-4813-bf28-dc3f5c776c31\",\"trace_id\":\"9d576391-5ec6-47d4-9c55-77e4dc0e5881\"}\n[2026-05-11 10:18:21] local.INFO: Running conference:monitor:count command for activities in (2026-05-11 10:16:00, 2026-05-11 10:18:00] {\"correlation_id\":\"5cd332f8-5b05-4813-bf28-dc3f5c776c31\",\"trace_id\":\"9d576391-5ec6-47d4-9c55-77e4dc0e5881\"}\n[2026-05-11 10:18:21] local.INFO: [conference:monitor:count] No activities found in (2026-05-11 10:16:00, 2026-05-11 10:18:00] {\"correlation_id\":\"5cd332f8-5b05-4813-bf28-dc3f5c776c31\",\"trace_id\":\"9d576391-5ec6-47d4-9c55-77e4dc0e5881\"}\n[2026-05-11 10:18:21] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"5cd332f8-5b05-4813-bf28-dc3f5c776c31\",\"trace_id\":\"9d576391-5ec6-47d4-9c55-77e4dc0e5881\"}\n[2026-05-11 10:18:25] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:retry-failed\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"5d165f52-8b9b-49f4-826c-5e6effb36469\",\"trace_id\":\"8d23eb87-94aa-45be-a25c-60adf651f65b\"}\n[2026-05-11 10:18:26] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:retry-failed\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"5d165f52-8b9b-49f4-826c-5e6effb36469\",\"trace_id\":\"8d23eb87-94aa-45be-a25c-60adf651f65b\"}\n[2026-05-11 10:18:26] local.INFO: [ EsUpdateProcessManager ] Finished updating entities in ES {\"worker\":\"\",\"peak_memory\":\"99.73 MB\",\"elapsed_seconds\":0.38,\"update_target\":\"activities\",\"should_iterate_again\":false} {\"correlation_id\":\"4ad05333-9afb-492e-9f0f-b2909ac45b32\",\"trace_id\":\"3d8feb24-b173-4158-b0a4-4cf33af85066\"}\n[2026-05-11 10:19:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"b818863b-2a43-41d9-8ff6-fee7c3d716bc\",\"trace_id\":\"247ba4af-b613-440c-94fe-1c5b9acb9a49\"}\n[2026-05-11 10:19:05] local.INFO: [ScheduleBotCommand] Number of activities to be captured: 0 {\"correlation_id\":\"b818863b-2a43-41d9-8ff6-fee7c3d716bc\",\"trace_id\":\"247ba4af-b613-440c-94fe-1c5b9acb9a49\"}\n[2026-05-11 10:19:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"b818863b-2a43-41d9-8ff6-fee7c3d716bc\",\"trace_id\":\"247ba4af-b613-440c-94fe-1c5b9acb9a49\"}\n[2026-05-11 10:19:07] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"ebc86a92-142f-437d-993d-b5babcf2cc26\",\"trace_id\":\"afbbde14-96ad-42a5-a9b8-acbb3e1d637a\"}\n[2026-05-11 10:19:07] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"ebc86a92-142f-437d-993d-b5babcf2cc26\",\"trace_id\":\"afbbde14-96ad-42a5-a9b8-acbb3e1d637a\"}\n[2026-05-11 10:19:08] local.NOTICE: Monitoring start {\"correlation_id\":\"e77a8f39-a88c-4046-abe4-817093d395f4\",\"trace_id\":\"17ae50a2-26b7-48ab-a9a4-1188e484d567\"}\n[2026-05-11 10:19:08] local.NOTICE: Monitoring end {\"correlation_id\":\"e77a8f39-a88c-4046-abe4-817093d395f4\",\"trace_id\":\"17ae50a2-26b7-48ab-a9a4-1188e484d567\"}\n[2026-05-11 10:19:09] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"82c9f998-b4ec-42a5-9114-b34b4ef4418e\",\"trace_id\":\"398aab71-a970-4adb-bfd2-e7003c988e9b\"}\n[2026-05-11 10:19:09] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"82c9f998-b4ec-42a5-9114-b34b4ef4418e\",\"trace_id\":\"398aab71-a970-4adb-bfd2-e7003c988e9b\"}\n[2026-05-11 10:19:10] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"00ff8a16-df56-4dbe-89ee-949f1fec10ae\",\"trace_id\":\"48f7dab8-39b8-47ff-badc-9e61a319de61\"}\n[2026-05-11 10:19:10] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"00ff8a16-df56-4dbe-89ee-949f1fec10ae\",\"trace_id\":\"48f7dab8-39b8-47ff-badc-9e61a319de61\"}\n[2026-05-11 10:19:10] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"00ff8a16-df56-4dbe-89ee-949f1fec10ae\",\"trace_id\":\"48f7dab8-39b8-47ff-badc-9e61a319de61\"}\n[2026-05-11 10:19:10] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"00ff8a16-df56-4dbe-89ee-949f1fec10ae\",\"trace_id\":\"48f7dab8-39b8-47ff-badc-9e61a319de61\"}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.011968086,"top":0.047885075,"width":0.024268618,"height":0.024740623},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
1814748303865906398
|
2919990469504940404
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
2
68
3
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot;
use HubSpot\Client\Crm\Deals\ApiException as DealApiException;
use HubSpot\Client\Crm\Contacts\ApiException as ContactApiException;
use HubSpot\Client\Crm\Companies\ApiException as CompanyApiException;
use HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectWithAssociations as ContactsWithAssociations;
use HubSpot\Client\Crm\Companies\Model\SimplePublicObjectWithAssociations as CompaniesWithAssociations;
use HubSpot\Client\Crm\Deals\Model\SimplePublicObjectWithAssociations as DealWithAssociations;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectInput;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectWithAssociations as ObjectWithAssociations;
use HubSpot\Client\Crm\Pipelines\Model\Error;
use HubSpot\Client\Crm\Pipelines\Model\PipelineStage;
use HubSpot\Client\Crm\Properties\Model\Property;
use HubSpot\Discovery\Discovery;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Crm\Field;
use Jiminny\Services\Crm\BaseClient;
use Jiminny\Services\Crm\Hubspot\DTO\Response\Owner;
use Jiminny\Services\SocialAccountService;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use SevenShores\Hubspot\Factory;
use SevenShores\Hubspot\Http\Response;
use Jiminny\Services\Crm\Hubspot\Pagination\HubspotPaginationService;
use Illuminate\Support\Facades\Redis;
use Throwable;
/**
* @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall
* @return T
*
* @throws RateLimitException
*/
private function executeRequest(callable $apiCall)
{
$cacheKey = $this->getRateLimitCacheKey();
$cachedRetryAfter = Redis::get($cacheKey);
if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {
throw new RateLimitException(
'Hubspot rate limit (cached circuit-breaker)',
(int) $cachedRetryAfter,
);
}
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'policy' => $this->parsePolicy($e),
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
private function getRateLimitCacheKey(): string
{
return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());
}
public function isHubspotRateLimit(Throwable $e): bool
{
if ($e instanceof BadRequest
|| $e instanceof DealApiException
|| $e instanceof ContactApiException
|| $e instanceof CompanyApiException
|| $e instanceof \GuzzleHttp\Exception\RequestException
) {
return (int) $e->getCode() === 429;
}
return false;
}
public function parseRetryAfter(Throwable $e): int
{
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
$policy = $this->parsePolicy($e);
if ($policy === 'TEN_SECONDLY_ROLLING') {
return 10;
}
if ($policy === 'SECONDLY') {
return 1;
}
if ($policy === 'DAILY_LIMIT') {
return 600;
}
$this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [
'exception_class' => get_class($e),
]);
return 10;
}
public function parsePolicy(Throwable $e): ?string
{
if (! method_exists($e, 'getResponseBody')) {
return null;
}
$body = $e->getResponseBody();
if (is_string($body)) {
$body = json_decode($body, true) ?? [];
}
if (! is_array($body)) {
return null;
}
$policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;
return is_string($policy) ? strtoupper($policy) : null;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* Execute a search request against HubSpot CRM objects with rate limiting.
*
* @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')
* @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.
* @return array The search response with 'results', 'total', 'paging' keys
* @throws RateLimitException When rate limit is hit
* @throws HubspotException On API errors
*/
public function search(string $objectType, array $payload): array
{
$endpoint = self::BASE_URL . "/crm/v3/objects/{$objectType}/search";
return $this->executeRequest(function () use ($endpoint, $payload) {
$response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);
return $response->toArray();
});
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
);
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
return $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
return $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
// } catch (RateLimitException $e) {
// throw $e;
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
Show Replace Field
Search History
Received 429 from API
New Line
Match Case
Words
Regex
Replace History
Replace
New Line
Preserve case
1/5
Previous Occurrence
Next Occurrence
Filter Search Results
Open in Window, Multiple Cursors
Click to highlight
Close
Sync Changes
Hide This Notification
Code changed:
Hide
523
Previous Highlighted Error
Next Highlighted Error
[2026-05-11 10:17:03] local.INFO: [MatchActivityCrmData] Starting CRM data matching {"activity":615092,"remote_search":true,"set_configuration":2,"old_state":{"lead_id":null,"contact_id":null,"account_id":26,"opportunity_id":22,"stage_id":89}} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:03] local.INFO: [ EsUpdateTarget ] Update single target {"target":"activities","purpose":"searchable-observer-update","entityId":615092} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:03] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {"entityType":"activities","entityId":615092,"collectionKey":"activities-for-update-priority","withPriority":true} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:03] local.INFO: [MatchActivityCrmData] Participants old state {"activity":615092,"participants":[{"id":1004102,"user_id":null,"contact_id":null,"lead_id":null},{"id":1004103,"user_id":89,"contact_id":null,"lead_id":null}]} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:03] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:03] local.INFO: [SocialAccountService] Token retrieved {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:03] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:03] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {"crm_provider":"hubspot","crm_owner":148,"team_id":2} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:03] local.INFO: [Prospect match] Cache miss, calling the API {"identifier_type":"email","identifier":"[EMAIL]"} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:03] local.INFO: [Hubspot] Failed to fetch contact {"email":"[EMAIL]","reason":"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/nikolay.nikolov%40jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response"} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:03] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {"identifier_type":"email","identifier":"[EMAIL]"} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.WARNING: [Hubspot] No retry-after header or policy name found, using default {"exception_class":"SevenShores\\Hubspot\\Exceptions\\BadRequest"} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.WARNING: [Hubspot] Received 429 from API {"team_id":2,"config_id":2,"retry_after":10,"policy":null,"reason":"Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response:
{\"status\":\"error\",\"message\":\"You have reached your secondly limit.\",\"errorType\":\"RATE_LIMIT\",\"correlationId\":\"019e168a-5 (truncated...)
"} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {"job_class":"Jiminny\\Jobs\\Crm\\MatchActivityCrmData","attempts":1,"retry_after":10,"delay":14} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {"activity":614436,"remote_search":true,"set_configuration":2,"old_state":{"lead_id":null,"contact_id":null,"account_id":26,"opportunity_id":22,"stage_id":89}} {"correlation_id":"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {"target":"activities","purpose":"searchable-observer-update","entityId":614436} {"correlation_id":"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {"entityType":"activities","entityId":614436,"collectionKey":"activities-for-update-priority","withPriority":true} {"correlation_id":"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {"activity":614436,"participants":[{"id":1002751,"user_id":null,"contact_id":null,"lead_id":null},{"id":1002752,"user_id":89,"contact_id":null,"lead_id":null}]} {"correlation_id":"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {"crm_provider":"hubspot","crm_owner":148,"team_id":2} {"correlation_id":"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {"identifier_type":"email","identifier":"[EMAIL]"} {"correlation_id":"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {"identifier_type":"email","identifier":"[EMAIL]"} {"correlation_id":"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {"job_class":"Jiminny\\Jobs\\Crm\\MatchActivityCrmData","attempts":1,"retry_after":10,"delay":14} {"correlation_id":"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {"activity":614382,"remote_search":true,"set_configuration":2,"old_state":{"lead_id":null,"contact_id":null,"account_id":26,"opportunity_id":22,"stage_id":89}} {"correlation_id":"78f847cf-6495-4054-b3d4-e179a133bd42","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {"target":"activities","purpose":"searchable-observer-update","entityId":614382} {"correlation_id":"78f847cf-6495-4054-b3d4-e179a133bd42","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {"entityType":"activities","entityId":614382,"collectionKey":"activities-for-update-priority","withPriority":true} {"correlation_id":"78f847cf-6495-4054-b3d4-e179a133bd42","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {"activity":614382,"participants":[{"id":1002632,"user_id":null,"contact_id":null,"lead_id":null},{"id":1002633,"user_id":89,"contact_id":null,"lead_id":null}]} {"correlation_id":"78f847cf-6495-4054-b3d4-e179a133bd42","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"78f847cf-6495-4054-b3d4-e179a133bd42","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"78f847cf-6495-4054-b3d4-e179a133bd42","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"78f847cf-6495-4054-b3d4-e179a133bd42","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {"crm_provider":"hubspot","crm_owner":148,"team_id":2} {"correlation_id":"78f847cf-6495-4054-b3d4-e179a133bd42","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {"identifier_type":"email","identifier":"[EMAIL]"} {"correlation_id":"78f847cf-6495-4054-b3d4-e179a133bd42","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {"identifier_type":"email","identifier":"[EMAIL]"} {"correlation_id":"78f847cf-6495-4054-b3d4-e179a133bd42","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {"job_class":"Jiminny\\Jobs\\Crm\\MatchActivityCrmData","attempts":1,"retry_after":10,"delay":11} {"correlation_id":"78f847cf-6495-4054-b3d4-e179a133bd42","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {"activity":614381,"remote_search":true,"set_configuration":2,"old_state":{"lead_id":null,"contact_id":null,"account_id":26,"opportunity_id":22,"stage_id":89}} {"correlation_id":"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {"target":"activities","purpose":"searchable-observer-update","entityId":614381} {"correlation_id":"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {"entityType":"activities","entityId":614381,"collectionKey":"activities-for-update-priority","withPriority":true} {"correlation_id":"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {"activity":614381,"participants":[{"id":1002630,"user_id":null,"contact_id":null,"lead_id":null},{"id":1002631,"user_id":89,"contact_id":null,"lead_id":null}]} {"correlation_id":"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {"crm_provider":"hubspot","crm_owner":148,"team_id":2} {"correlation_id":"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {"identifier_type":"email","identifier":"[EMAIL]"} {"correlation_id":"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {"identifier_type":"email","identifier":"[EMAIL]"} {"correlation_id":"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {"job_class":"Jiminny\\Jobs\\Crm\\MatchActivityCrmData","attempts":1,"retry_after":10,"delay":11} {"correlation_id":"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {"activity":614378,"remote_search":true,"set_configuration":2,"old_state":{"lead_id":null,"contact_id":6167,"account_id":null,"opportunity_id":null,"stage_id":null}} {"correlation_id":"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {"target":"activities","purpose":"searchable-observer-update","entityId":614378} {"correlation_id":"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {"entityType":"activities","entityId":614378,"collectionKey":"activities-for-update-priority","withPriority":true} {"correlation_id":"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {"activity":614378,"participants":[{"id":1002623,"user_id":null,"contact_id":null,"lead_id":null},{"id":1002624,"user_id":null,"contact_id":6167,"lead_id":null},{"id":1002625,"user_id":89,"contact_id":null,"lead_id":null}]} {"correlation_id":"2522b1c9-...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
17481
|
774
|
43
|
2026-05-11T10:24:22.311756+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778495062311_m2.jpg...
|
Firefox
|
Screenpipe — Archive — Personal
|
True
|
app.screenpipe.lakylak.xyz
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
New Tab
New Tab
Screenpipe — Archive
Screenpipe — New Tab
New Tab
Screenpipe — Archive
Screenpipe — Archive
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Screenpipe [archive.db · 12323.6MB]
Screenpipe
[archive.db · 12323.6MB]
Activity
Search
Audio
Work Report
Timetable
AI Summary
Date
07
/
05
/
2026
Calendar
SECONDLY
Search
AND also
second required term — both must appear in same result (optional)
Source
App
Date
dd
/
mm
/
yyyy
Calendar
(blank = all dates)
From
--
:
--
To
--
:
--
Only apps
any app (blank = all)
▾
Skip apps
none skipped
▾
FTS tip: single words work best · "exact phrase" · term1 OR term2 · use AND also for required second term · times are in your local timezone · click any result to expand
49 results
▶ video
7 May 19:25
Screen
PhpStorm
/ faVsco.js – Client.php
⏱ Timeline
...true) ??
:SpolicyName = $body
'policyName'
?? Sbody
'policy'
?? null:Map pollcy names to retry delaysif (SpolicvName === 'TEN
SECONDLY
_ROLLING' |I SpolicvName === 'ten
secondly
rolling') {
… (click to expand)
▶ video
7 May 19:10
Screen
PhpStorm
/ faVsco.js – Client.php
⏱ Timeline
...true) ??
:Snolievlane = Sbod/LUpoltiev/lane:1 22 Shody
LnolieyL1L.22 п11rao nolicy names to retry delav1f SpoLicvName ==='TEN
SECONDLY
ROLLING' |I SpolicvName === 'ten
secondly
rolling') {Le
… (click to expand)
7 May 17:24
Typed
Firefox
text
⏱ Timeline
.
7 May 17:23
Typed
Firefox
text
⏱ Timeline
7 May 17:22
Typed
Firefox
text
⏱ Timeline
.
7 May 17:22
Typed
Firefox
text
⏱ Timeline
'
7 May 17:21
Typed
Firefox
text
⏱ Timeline
7 May 17:20
Typed
Firefox
text
⏱ Timeline
7 May 17:19
Typed
Firefox
text
⏱ Timeline
7 May 17:17
Typed
Firefox
text
⏱ Timeline
7 May 17:17
Typed
Firefox
text
⏱ Timeline
$
7 May 17:17
Typed
Firefox
text
⏱ Timeline
;
7 May 17:17
Typed
Firefox
text
⏱ Timeline
=
7 May 17:16
Typed
Firefox
text
⏱ Timeline
:
7 May 17:16
Typed
Firefox
text
⏱ Timeline
7 May 17:15
Typed
Firefox
text
⏱ Timeline
.
7 May 17:15
Typed
Firefox
text
⏱ Timeline
7 May 17:14
Typed
Firefox
text
⏱ Timeline
7 May 17:14
Typed
Firefox
text
⏱ Timeline
.
7 May 17:10
Typed
Firefox
text
⏱ Timeline
7 May 17:09
Typed
Firefox
text
⏱ Timeline
7 May 17:08
Typed
Firefox
text
⏱ Timeline
7 May 17:07
Typed
Firefox
text
⏱ Timeline
7 May 14:13
Typed
Claude
text
⏱ Timeline
secondly
7 May 10:58
Typed
clipboard
⏱ Timeline
...search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your
secondly
limit.","errorType":"RATE_LIMIT","correlationId":"019dffc4-4 (truncated...)
7 May 10:41
Typed
clipboard
⏱ Timeline
...search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your
secondly
limit.","errorType":"RATE_LIMIT","correlationId":"019dffc4-4 (truncated...)
7 May 10:41
Typed
Firefox
text
⏱ Timeline
7 May 10:41
Typed
Firefox
text
⏱ Timeline
)
7 May 10:41
Typed
Firefox
text
⏱ Timeline
,
7 May 10:41
Typed
Firefox
text
⏱ Timeline
(
7 May 10:38
Typed
Firefox
text
⏱ Timeline
▶ video
22 Apr 12:58
Screen
Firefox
/ Jiminny — Work
app.staging.jiminny.com/ai-reports/pdf/582d4b50-8cd3-42a9-9819-d676ff8f3b43
⏱ Timeline
...Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your
secondly
limit.","erro
… (click to expand)
▶ video
22 Apr 12:50
Screen
Firefox
/ Pull requests · jiminny/app — Work
github.com/jiminny/app/pull/11998
⏱ Timeline
...Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your
secondly
limit.","erro...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"New Tab","depth":4,"bounds":{"left":0.28823137,"top":0.0518755,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New Tab","depth":5,"bounds":{"left":0.30152926,"top":0.06304868,"width":0.014960106,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Screenpipe — Archive","depth":4,"bounds":{"left":0.28823137,"top":0.08459697,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Screenpipe — Archive","depth":5,"bounds":{"left":0.30152926,"top":0.09577015,"width":0.037898935,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.38962767,"top":0.09177973,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.29105717,"top":0.118914604,"width":0.108211435,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.29105717,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"bounds":{"left":0.3020279,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.3131649,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.32430187,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bitwarden","depth":6,"bounds":{"left":0.33543882,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Screenpipe [archive.db · 12323.6MB]","depth":7,"bounds":{"left":0.4085771,"top":0.061452515,"width":0.06698803,"height":0.017956903},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Screenpipe","depth":8,"bounds":{"left":0.4085771,"top":0.06304868,"width":0.027759308,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"[archive.db · 12323.6MB]","depth":9,"bounds":{"left":0.43766624,"top":0.06703911,"width":0.037898935,"height":0.009976057},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Activity","depth":7,"bounds":{"left":0.48021942,"top":0.059856344,"width":0.024767287,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Search","depth":7,"bounds":{"left":0.5056516,"top":0.059856344,"width":0.023769947,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Audio","depth":7,"bounds":{"left":0.53008646,"top":0.059856344,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"No audio data in this database","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Work Report","depth":7,"bounds":{"left":0.55169547,"top":0.059856344,"width":0.03507314,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Timetable","depth":7,"bounds":{"left":0.5874335,"top":0.059856344,"width":0.029753989,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Summary","depth":7,"bounds":{"left":0.6178524,"top":0.059856344,"width":0.034075797,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Date","depth":8,"bounds":{"left":0.93849736,"top":0.0650439,"width":0.008144947,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"07","depth":9,"bounds":{"left":0.9552859,"top":0.06464485,"width":0.0048204786,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":8,"bounds":{"left":0.96110374,"top":0.06464485,"width":0.0023271276,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"05","depth":9,"bounds":{"left":0.9644282,"top":0.06464485,"width":0.0048204786,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":8,"bounds":{"left":0.970246,"top":0.06464485,"width":0.002493351,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2026","depth":9,"bounds":{"left":0.9737367,"top":0.06464485,"width":0.009474734,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Calendar","depth":8,"bounds":{"left":0.98454124,"top":0.0650439,"width":0.0051529254,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"SECONDLY","depth":8,"bounds":{"left":0.4965093,"top":0.11412609,"width":0.38131648,"height":0.025538707},"on_screen":true,"value":"SECONDLY","help_text":"","role_description":"text field","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Search","depth":8,"bounds":{"left":0.88048536,"top":0.11412609,"width":0.024933511,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AND also","depth":9,"bounds":{"left":0.4965093,"top":0.15522745,"width":0.01662234,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXTextField","text":"second required term — both must appear in same result (optional)","depth":8,"bounds":{"left":0.51579124,"top":0.14764565,"width":0.38962767,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"text field","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Source","depth":9,"bounds":{"left":0.4965093,"top":0.18754987,"width":0.012300532,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"App","depth":9,"bounds":{"left":0.58427525,"top":0.18754987,"width":0.006981383,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Date","depth":9,"bounds":{"left":0.6431183,"top":0.18754987,"width":0.008144947,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"dd","depth":10,"bounds":{"left":0.65791225,"top":0.18715084,"width":0.0048204786,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":9,"bounds":{"left":0.66373,"top":0.18715084,"width":0.002493351,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"mm","depth":10,"bounds":{"left":0.6672208,"top":0.18715084,"width":0.004654255,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":9,"bounds":{"left":0.67287236,"top":0.18715084,"width":0.002493351,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"yyyy","depth":10,"bounds":{"left":0.67636305,"top":0.18715084,"width":0.009640957,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Calendar","depth":9,"bounds":{"left":0.6871675,"top":0.18754987,"width":0.005319149,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"(blank = all dates)","depth":9,"bounds":{"left":0.69863695,"top":0.18794893,"width":0.028756648,"height":0.009976057},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"From","depth":9,"bounds":{"left":0.7300532,"top":0.18754987,"width":0.008976064,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"--","depth":10,"bounds":{"left":0.7456782,"top":0.18715084,"width":0.004654255,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":9,"bounds":{"left":0.7513298,"top":0.18715084,"width":0.002493351,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"--","depth":10,"bounds":{"left":0.75482047,"top":0.18715084,"width":0.0048204786,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"To","depth":9,"bounds":{"left":0.7742686,"top":0.18754987,"width":0.004155585,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"--","depth":10,"bounds":{"left":0.78507316,"top":0.18715084,"width":0.004654255,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":9,"bounds":{"left":0.79072475,"top":0.18715084,"width":0.002493351,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"--","depth":10,"bounds":{"left":0.79421544,"top":0.18715084,"width":0.0048204786,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Only apps","depth":9,"bounds":{"left":0.4965093,"top":0.21588188,"width":0.017453458,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"any app (blank = all)","depth":11,"bounds":{"left":0.51961434,"top":0.2150838,"width":0.038065158,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"▾","depth":11,"bounds":{"left":0.5718085,"top":0.21628092,"width":0.0016622341,"height":0.009976057},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Skip apps","depth":9,"bounds":{"left":0.5817819,"top":0.21588188,"width":0.017121011,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"none skipped","depth":11,"bounds":{"left":0.60455453,"top":0.2150838,"width":0.025265958,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"▾","depth":11,"bounds":{"left":0.65674865,"top":0.21628092,"width":0.0016622341,"height":0.009976057},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"FTS tip: single words work best · \"exact phrase\" · term1 OR term2 · use AND also for required second term · times are in your local timezone · click any result to expand","depth":9,"bounds":{"left":0.4965093,"top":0.23902634,"width":0.29055852,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"49 results","depth":10,"bounds":{"left":0.4978391,"top":0.29209897,"width":0.017453458,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"▶ video","depth":10,"bounds":{"left":0.50964093,"top":0.3367917,"width":0.012300532,"height":0.009976057},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"7 May 19:25","depth":11,"bounds":{"left":0.5340758,"top":0.32043096,"width":0.021110373,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Screen","depth":11,"bounds":{"left":0.55851066,"top":0.32202715,"width":0.010139627,"height":0.008778931},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"PhpStorm","depth":12,"bounds":{"left":0.57130986,"top":0.32043096,"width":0.01861702,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/ faVsco.js – Client.php","depth":11,"bounds":{"left":0.5909242,"top":0.32043096,"width":0.039893616,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"bounds":{"left":0.8784907,"top":0.31923383,"width":0.022606382,"height":0.014764565},"on_screen":true,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"...true) ??","depth":11,"bounds":{"left":0.5340758,"top":0.339585,"width":0.020279255,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":SpolicyName = $body","depth":11,"bounds":{"left":0.55502,"top":0.339585,"width":0.045545213,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'policyName'","depth":12,"bounds":{"left":0.6008976,"top":0.339585,"width":0.026097074,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"?? Sbody","depth":11,"bounds":{"left":0.62732714,"top":0.339585,"width":0.019614361,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'policy'","depth":12,"bounds":{"left":0.64727396,"top":0.339585,"width":0.014461436,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"?? null:Map pollcy names to retry delaysif (SpolicvName === 'TEN","depth":11,"bounds":{"left":0.66206783,"top":0.339585,"width":0.1349734,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SECONDLY","depth":12,"bounds":{"left":0.79737365,"top":0.339585,"width":0.022772606,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"_ROLLING' |I SpolicvName === 'ten","depth":11,"bounds":{"left":0.82047874,"top":0.339585,"width":0.07263963,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"secondly","depth":12,"bounds":{"left":0.5344083,"top":0.35514766,"width":0.018118352,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"rolling') {","depth":11,"bounds":{"left":0.55285907,"top":0.35514766,"width":0.019281914,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"… (click to expand)","depth":11,"bounds":{"left":0.57214093,"top":0.35514766,"width":0.038231384,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"▶ video","depth":10,"bounds":{"left":0.50964093,"top":0.40901837,"width":0.012300532,"height":0.009976057},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"7 May 19:10","depth":11,"bounds":{"left":0.5340758,"top":0.3926576,"width":0.020611702,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Screen","depth":11,"bounds":{"left":0.55801195,"top":0.3942538,"width":0.010139627,"height":0.008778931},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"PhpStorm","depth":12,"bounds":{"left":0.57081115,"top":0.3926576,"width":0.01861702,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/ faVsco.js – Client.php","depth":11,"bounds":{"left":0.59042555,"top":0.3926576,"width":0.039893616,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"bounds":{"left":0.8784907,"top":0.3914605,"width":0.022606382,"height":0.014764565},"on_screen":true,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"...true) ??","depth":11,"bounds":{"left":0.5340758,"top":0.41181165,"width":0.020279255,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":Snolievlane = Sbod/LUpoltiev/lane:1 22 Shody","depth":11,"bounds":{"left":0.55502,"top":0.41181165,"width":0.09424867,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"LnolieyL1L.22 п11rao nolicy names to retry delav1f SpoLicvName ==='TEN","depth":12,"bounds":{"left":0.64960104,"top":0.41181165,"width":0.14943483,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SECONDLY","depth":13,"bounds":{"left":0.7993683,"top":0.41181165,"width":0.022772606,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ROLLING' |I SpolicvName === 'ten","depth":12,"bounds":{"left":0.8224734,"top":0.41181165,"width":0.07014628,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"secondly","depth":13,"bounds":{"left":0.5344083,"top":0.4273743,"width":0.018118352,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"rolling') {Le","depth":12,"bounds":{"left":0.55285907,"top":0.4273743,"width":0.024102394,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"… (click to expand)","depth":12,"bounds":{"left":0.57696146,"top":0.4273743,"width":0.038065158,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"7 May 17:24","depth":11,"bounds":{"left":0.5008311,"top":0.46488428,"width":0.020777926,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Typed","depth":11,"bounds":{"left":0.5249335,"top":0.46648043,"width":0.008976064,"height":0.008778931},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"bounds":{"left":0.53673536,"top":0.46488428,"width":0.012799202,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"text","depth":11,"bounds":{"left":0.5505319,"top":0.46568236,"width":0.006150266,"height":0.009976057},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"bounds":{"left":0.8784907,"top":0.46368715,"width":0.022606382,"height":0.014764565},"on_screen":true,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":".","depth":11,"bounds":{"left":0.5008311,"top":0.4840383,"width":0.0013297872,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"7 May 17:23","depth":11,"bounds":{"left":0.5008311,"top":0.5215483,"width":0.020777926,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Typed","depth":11,"bounds":{"left":0.5249335,"top":0.5231444,"width":0.008976064,"height":0.008778931},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"bounds":{"left":0.5365692,"top":0.5215483,"width":0.012965426,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"text","depth":11,"bounds":{"left":0.5505319,"top":0.5223464,"width":0.006150266,"height":0.009976057},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"bounds":{"left":0.8784907,"top":0.5203512,"width":0.022606382,"height":0.014764565},"on_screen":true,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"7 May 17:22","depth":11,"bounds":{"left":0.5008311,"top":0.56264967,"width":0.020777926,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Typed","depth":11,"bounds":{"left":0.5249335,"top":0.5642458,"width":0.008976064,"height":0.008778931},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"bounds":{"left":0.5365692,"top":0.56264967,"width":0.012799202,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"text","depth":11,"bounds":{"left":0.5503657,"top":0.5634477,"width":0.006150266,"height":0.009976057},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"bounds":{"left":0.8784907,"top":0.5614525,"width":0.022606382,"height":0.014764565},"on_screen":true,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":".","depth":11,"bounds":{"left":0.5008311,"top":0.5818037,"width":0.0013297872,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"7 May 17:22","depth":11,"bounds":{"left":0.5008311,"top":0.61931366,"width":0.020777926,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Typed","depth":11,"bounds":{"left":0.5249335,"top":0.6209098,"width":0.008976064,"height":0.008778931},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"bounds":{"left":0.5365692,"top":0.61931366,"width":0.012799202,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"text","depth":11,"bounds":{"left":0.5503657,"top":0.6201117,"width":0.006150266,"height":0.009976057},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"bounds":{"left":0.8784907,"top":0.6181165,"width":0.022606382,"height":0.014764565},"on_screen":true,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"'","depth":11,"bounds":{"left":0.5008311,"top":0.63846767,"width":0.0013297872,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"7 May 17:21","depth":11,"bounds":{"left":0.5008311,"top":0.67597765,"width":0.020279255,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Typed","depth":11,"bounds":{"left":0.52443486,"top":0.6775738,"width":0.008976064,"height":0.008778931},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"bounds":{"left":0.53607047,"top":0.67597765,"width":0.012799202,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"text","depth":11,"bounds":{"left":0.54986703,"top":0.67677575,"width":0.006150266,"height":0.009976057},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"bounds":{"left":0.8784907,"top":0.67478055,"width":0.022606382,"height":0.014764565},"on_screen":true,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"7 May 17:20","depth":11,"bounds":{"left":0.5008311,"top":0.717079,"width":0.020777926,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Typed","depth":11,"bounds":{"left":0.5249335,"top":0.7186752,"width":0.008976064,"height":0.008778931},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"bounds":{"left":0.53673536,"top":0.717079,"width":0.012799202,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"text","depth":11,"bounds":{"left":0.5505319,"top":0.7178771,"width":0.006150266,"height":0.009976057},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"bounds":{"left":0.8784907,"top":0.7158819,"width":0.022606382,"height":0.014764565},"on_screen":true,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"7 May 17:19","depth":11,"bounds":{"left":0.5008311,"top":0.7581804,"width":0.020279255,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Typed","depth":11,"bounds":{"left":0.52443486,"top":0.75977653,"width":0.008976064,"height":0.008778931},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"bounds":{"left":0.53607047,"top":0.7581804,"width":0.012965426,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"text","depth":11,"bounds":{"left":0.5500333,"top":0.7589784,"width":0.006150266,"height":0.009976057},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"bounds":{"left":0.8784907,"top":0.7569832,"width":0.022606382,"height":0.014764565},"on_screen":true,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"7 May 17:17","depth":11,"bounds":{"left":0.5008311,"top":0.7992817,"width":0.020113032,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Typed","depth":11,"bounds":{"left":0.5242686,"top":0.80087787,"width":0.008976064,"height":0.008778931},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"bounds":{"left":0.5359042,"top":0.7992817,"width":0.012799202,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"text","depth":11,"bounds":{"left":0.5497008,"top":0.8000798,"width":0.006150266,"height":0.009976057},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"bounds":{"left":0.8784907,"top":0.7980846,"width":0.022606382,"height":0.014764565},"on_screen":true,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"7 May 17:17","depth":11,"bounds":{"left":0.5008311,"top":0.84038305,"width":0.020113032,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Typed","depth":11,"bounds":{"left":0.5242686,"top":0.84197927,"width":0.008976064,"height":0.008778931},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"bounds":{"left":0.5359042,"top":0.84038305,"width":0.012799202,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"text","depth":11,"bounds":{"left":0.5497008,"top":0.84118116,"width":0.006150266,"height":0.009976057},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"bounds":{"left":0.8784907,"top":0.83918595,"width":0.022606382,"height":0.014764565},"on_screen":true,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"$","depth":11,"bounds":{"left":0.5008311,"top":0.8595371,"width":0.0026595744,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"7 May 17:17","depth":11,"bounds":{"left":0.5008311,"top":0.8970471,"width":0.020113032,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Typed","depth":11,"bounds":{"left":0.5242686,"top":0.89864326,"width":0.008976064,"height":0.008778931},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"bounds":{"left":0.5359042,"top":0.8970471,"width":0.012799202,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"text","depth":11,"bounds":{"left":0.5497008,"top":0.89784515,"width":0.006150266,"height":0.009976057},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"bounds":{"left":0.8784907,"top":0.89584994,"width":0.022606382,"height":0.014764565},"on_screen":true,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":";","depth":11,"bounds":{"left":0.5008311,"top":0.9162011,"width":0.0013297872,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"7 May 17:17","depth":11,"bounds":{"left":0.5008311,"top":0.9537111,"width":0.020113032,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Typed","depth":11,"bounds":{"left":0.5242686,"top":0.95530725,"width":0.008976064,"height":0.008778931},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"bounds":{"left":0.5359042,"top":0.9537111,"width":0.012799202,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"text","depth":11,"bounds":{"left":0.5497008,"top":0.9545092,"width":0.006150266,"height":0.009976057},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"bounds":{"left":0.8784907,"top":0.952514,"width":0.022606382,"height":0.014764565},"on_screen":true,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"=","depth":11,"bounds":{"left":0.5008311,"top":0.9728651,"width":0.0026595744,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"7 May 17:16","depth":11,"bounds":{"left":0.5008311,"top":1.0,"width":0.020279255,"height":-0.010375142},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Typed","depth":11,"bounds":{"left":0.52443486,"top":1.0,"width":0.008976064,"height":-0.011971235},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"bounds":{"left":0.53607047,"top":1.0,"width":0.012965426,"height":-0.010375142},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"text","depth":11,"bounds":{"left":0.5500333,"top":1.0,"width":0.006150266,"height":-0.011173129},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"bounds":{"left":0.8784907,"top":1.0,"width":0.022606382,"height":-0.009177923},"on_screen":false,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":":","depth":11,"bounds":{"left":0.5008311,"top":1.0,"width":0.0013297872,"height":-0.029529095},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"7 May 17:16","depth":11,"bounds":{"left":0.5008311,"top":1.0,"width":0.020279255,"height":-0.06703913},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Typed","depth":11,"bounds":{"left":0.52443486,"top":1.0,"width":0.008976064,"height":-0.068635225},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"bounds":{"left":0.53607047,"top":1.0,"width":0.012965426,"height":-0.06703913},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"text","depth":11,"bounds":{"left":0.5500333,"top":1.0,"width":0.006150266,"height":-0.06783724},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"bounds":{"left":0.8784907,"top":1.0,"width":0.022606382,"height":-0.06584203},"on_screen":false,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"7 May 17:15","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Typed","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"text","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":false,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":".","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"7 May 17:15","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Typed","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"text","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":false,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"7 May 17:14","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Typed","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"text","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":false,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"7 May 17:14","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Typed","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"text","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":false,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":".","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"7 May 17:10","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Typed","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"text","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":false,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"7 May 17:09","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Typed","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"text","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":false,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"7 May 17:08","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Typed","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"text","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":false,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"7 May 17:07","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Typed","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"text","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":false,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"7 May 14:13","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Typed","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Claude","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"text","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":false,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"secondly","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"7 May 10:58","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Typed","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"clipboard","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":false,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"...search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"secondly","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"limit.\",\"errorType\":\"RATE_LIMIT\",\"correlationId\":\"019dffc4-4 (truncated...)","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"7 May 10:41","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Typed","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"clipboard","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":false,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"...search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"secondly","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"limit.\",\"errorType\":\"RATE_LIMIT\",\"correlationId\":\"019dffc4-4 (truncated...)","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"7 May 10:41","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Typed","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"text","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":false,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"7 May 10:41","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Typed","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"text","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":false,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":")","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"7 May 10:41","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Typed","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"text","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":false,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":",","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"7 May 10:41","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Typed","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"text","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":false,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"(","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"7 May 10:38","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Typed","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"text","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":false,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"▶ video","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"22 Apr 12:58","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Screen","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/ Jiminny — Work","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app.staging.jiminny.com/ai-reports/pdf/582d4b50-8cd3-42a9-9819-d676ff8f3b43","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":false,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"...Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"secondly","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"limit.\",\"erro","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"… (click to expand)","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"▶ video","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"22 Apr 12:50","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Screen","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/ Pull requests · jiminny/app — Work","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"github.com/jiminny/app/pull/11998","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":false,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"...Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"secondly","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"limit.\",\"erro","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-6533080334848067131
|
6842771759681222921
|
visual_change
|
accessibility
|
NULL
|
New Tab
New Tab
Screenpipe — Archive
Screenpipe — New Tab
New Tab
Screenpipe — Archive
Screenpipe — Archive
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Screenpipe [archive.db · 12323.6MB]
Screenpipe
[archive.db · 12323.6MB]
Activity
Search
Audio
Work Report
Timetable
AI Summary
Date
07
/
05
/
2026
Calendar
SECONDLY
Search
AND also
second required term — both must appear in same result (optional)
Source
App
Date
dd
/
mm
/
yyyy
Calendar
(blank = all dates)
From
--
:
--
To
--
:
--
Only apps
any app (blank = all)
▾
Skip apps
none skipped
▾
FTS tip: single words work best · "exact phrase" · term1 OR term2 · use AND also for required second term · times are in your local timezone · click any result to expand
49 results
▶ video
7 May 19:25
Screen
PhpStorm
/ faVsco.js – Client.php
⏱ Timeline
...true) ??
:SpolicyName = $body
'policyName'
?? Sbody
'policy'
?? null:Map pollcy names to retry delaysif (SpolicvName === 'TEN
SECONDLY
_ROLLING' |I SpolicvName === 'ten
secondly
rolling') {
… (click to expand)
▶ video
7 May 19:10
Screen
PhpStorm
/ faVsco.js – Client.php
⏱ Timeline
...true) ??
:Snolievlane = Sbod/LUpoltiev/lane:1 22 Shody
LnolieyL1L.22 п11rao nolicy names to retry delav1f SpoLicvName ==='TEN
SECONDLY
ROLLING' |I SpolicvName === 'ten
secondly
rolling') {Le
… (click to expand)
7 May 17:24
Typed
Firefox
text
⏱ Timeline
.
7 May 17:23
Typed
Firefox
text
⏱ Timeline
7 May 17:22
Typed
Firefox
text
⏱ Timeline
.
7 May 17:22
Typed
Firefox
text
⏱ Timeline
'
7 May 17:21
Typed
Firefox
text
⏱ Timeline
7 May 17:20
Typed
Firefox
text
⏱ Timeline
7 May 17:19
Typed
Firefox
text
⏱ Timeline
7 May 17:17
Typed
Firefox
text
⏱ Timeline
7 May 17:17
Typed
Firefox
text
⏱ Timeline
$
7 May 17:17
Typed
Firefox
text
⏱ Timeline
;
7 May 17:17
Typed
Firefox
text
⏱ Timeline
=
7 May 17:16
Typed
Firefox
text
⏱ Timeline
:
7 May 17:16
Typed
Firefox
text
⏱ Timeline
7 May 17:15
Typed
Firefox
text
⏱ Timeline
.
7 May 17:15
Typed
Firefox
text
⏱ Timeline
7 May 17:14
Typed
Firefox
text
⏱ Timeline
7 May 17:14
Typed
Firefox
text
⏱ Timeline
.
7 May 17:10
Typed
Firefox
text
⏱ Timeline
7 May 17:09
Typed
Firefox
text
⏱ Timeline
7 May 17:08
Typed
Firefox
text
⏱ Timeline
7 May 17:07
Typed
Firefox
text
⏱ Timeline
7 May 14:13
Typed
Claude
text
⏱ Timeline
secondly
7 May 10:58
Typed
clipboard
⏱ Timeline
...search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your
secondly
limit.","errorType":"RATE_LIMIT","correlationId":"019dffc4-4 (truncated...)
7 May 10:41
Typed
clipboard
⏱ Timeline
...search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your
secondly
limit.","errorType":"RATE_LIMIT","correlationId":"019dffc4-4 (truncated...)
7 May 10:41
Typed
Firefox
text
⏱ Timeline
7 May 10:41
Typed
Firefox
text
⏱ Timeline
)
7 May 10:41
Typed
Firefox
text
⏱ Timeline
,
7 May 10:41
Typed
Firefox
text
⏱ Timeline
(
7 May 10:38
Typed
Firefox
text
⏱ Timeline
▶ video
22 Apr 12:58
Screen
Firefox
/ Jiminny — Work
app.staging.jiminny.com/ai-reports/pdf/582d4b50-8cd3-42a9-9819-d676ff8f3b43
⏱ Timeline
...Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your
secondly
limit.","erro
… (click to expand)
▶ video
22 Apr 12:50
Screen
Firefox
/ Pull requests · jiminny/app — Work
github.com/jiminny/app/pull/11998
⏱ Timeline
...Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your
secondly
limit.","erro...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
17496
|
772
|
43
|
2026-05-11T10:24:28.924106+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778495068924_m1.jpg...
|
Firefox
|
Screenpipe — Archive — Personal
|
True
|
app.screenpipe.lakylak.xyz
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
New Tab
New Tab
Screenpipe — Archive
Screenpipe — New Tab
New Tab
Screenpipe — Archive
Screenpipe — Archive
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Screenpipe [archive.db · 12323.6MB]
Screenpipe
[archive.db · 12323.6MB]
Activity
Search
Audio
Work Report
Timetable
AI Summary
Date
07
/
05
/
2026
Calendar
SECONDLY
Search
AND also
second required term — both must appear in same result (optional)
Source
App
Date
dd
/
mm
/
yyyy
Calendar
(blank = all dates)
From
--
:
--
To
--
:
--
Only apps
any app (blank = all)
▾
Skip apps
none skipped
▾
FTS tip: single words work best · "exact phrase" · term1 OR term2 · use AND also for required second term · times are in your local timezone · click any result to expand
49 results
▶ video
7 May 19:25
Screen
PhpStorm
/ faVsco.js – Client.php
⏱ Timeline
...true) ??
:SpolicyName = $body
'policyName'
?? Sbody
'policy'
?? null:Map pollcy names to retry delaysif (SpolicvName === 'TEN
SECONDLY
_ROLLING' |I SpolicvName === 'ten
secondly
rolling') {
… (click to expand)
▶ video
7 May 19:10
Screen
PhpStorm
/ faVsco.js – Client.php
⏱ Timeline
...true) ??
:Snolievlane = Sbod/LUpoltiev/lane:1 22 Shody
LnolieyL1L.22 п11rao nolicy names to retry delav1f SpoLicvName ==='TEN
SECONDLY
ROLLING' |I SpolicvName === 'ten
secondly
rolling') {Le
… (click to expand)
7 May 17:24
Typed
Firefox
text
⏱ Timeline
.
7 May 17:23
Typed
Firefox
text
⏱ Timeline
7 May 17:22
Typed
Firefox
text
⏱ Timeline
.
7 May 17:22
Typed
Firefox
text
⏱ Timeline
'
7 May 17:21
Typed
Firefox
text
⏱ Timeline
7 May 17:20
Typed
Firefox
text
⏱ Timeline
7 May 17:19
Typed
Firefox
text
⏱ Timeline
7 May 17:17
Typed
Firefox
text
⏱ Timeline
7 May 17:17
Typed
Firefox
text
⏱ Timeline
$
7 May 17:17
Typed
Firefox
text
⏱ Timeline
;
7 May 17:17
Typed
Firefox
text
⏱ Timeline
=
7 May 17:16
Typed
Firefox
text
⏱ Timeline
:
7 May 17:16
Typed
Firefox
text
⏱ Timeline
7 May 17:15
Typed
Firefox
text
⏱ Timeline
.
7 May 17:15
Typed
Firefox
text
⏱ Timeline
7 May 17:14
Typed
Firefox
text
⏱ Timeline
7 May 17:14
Typed
Firefox
text
⏱ Timeline
.
7 May 17:10
Typed
Firefox
text
⏱ Timeline
7 May 17:09
Typed
Firefox
text
⏱ Timeline
7 May 17:08
Typed
Firefox
text
⏱ Timeline
7 May 17:07
Typed
Firefox
text
⏱ Timeline
7 May 14:13
Typed
Claude
text
⏱ Timeline
secondly
7 May 10:58
Typed
clipboard
⏱ Timeline
...search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your
secondly
limit.","errorType":"RATE_LIMIT","correlationId":"019dffc4-4 (truncated...)
7 May 10:41
Typed
clipboard
⏱ Timeline
...search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your
secondly
limit.","errorType":"RATE_LIMIT","correlationId":"019dffc4-4 (truncated...)
7 May 10:41
Typed
Firefox
text
⏱ Timeline
7 May 10:41
Typed
Firefox
text
⏱ Timeline
)
7 May 10:41
Typed
Firefox
text
⏱ Timeline
,
7 May 10:41
Typed
Firefox
text
⏱ Timeline
(
7 May 10:38
Typed
Firefox
text
⏱ Timeline
▶ video
22 Apr 12:58
Screen
Firefox
/ Jiminny — Work
app.staging.jiminny.com/ai-reports/pdf/582d4b50-8cd3-42a9-9819-d676ff8f3b43
⏱ Timeline
...Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your
secondly
limit.","erro
… (click to expand)
▶ video
22 Apr 12:50
Screen
Firefox
/ Pull requests · jiminny/app — Work
github.com/jiminny/app/pull/11998
⏱ Timeline
...Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your
secondly
limit.","erro
… (click to expand)
▶ video
22 Apr 12:44
Screen
Firefox
/ Platform Sprint 2 Q2 - Platform Team - Scrum Board
jiminny.atlassian.net/jira/software/c/projects/JY/boards/37
⏱ Timeline
...Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your
secondly
limit.","erro
… (click to expand)
22 Apr 12:42
Typed
clipboard
⏱ Timeline
...search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your
secondly
limit.","errorType":"RATE_LIMIT","correlationId":"019db2b6-c (truncated...)
▶ video
22 Apr 12:42
Screen
Firefox
/ SevenShores\Hubspot\Exceptions\BadRequest: Client
jiminny.sentry.io/issues/7007366572/events/38fa421c52fc432b92bfc347df23b251/
⏱ Timeline
...Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your
secondly
limit.","erro
… (click to expand)
▶ video
22 Apr 12:41
Screen
Firefox
/ SevenShores\Hubspot\Exceptions\BadRequest: Client
jiminny.sentry.io/issues/7007366572/events/?project=82419&referrer=slack
⏱ Timeline
...Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your
secondly
limit.","erro
… (click to expand)
▶ video
22 Apr 12:40
Screen
Firefox
/ SevenShores\Hubspot\Exceptions\BadRequest: Client
jiminny.sentry.io/issues/7007366572/events/?project=82419&referrer=slack
⏱ Timeline
...Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your
secondly
limit.","erro
… (click to expand)
▶ video
22 Apr 12:39
Screen
Firefox
/ Pipelines - /app — Work
app.circleci.com/pipelines/github/jiminny/app
⏱ Timeline
...Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your
secondly
limit.","erro
… (click to expand)
▶ video
22 Apr 12:20
Screen
Firefox
/ Platform Sprint 2 Q2 - Platform Team - Scrum Board
jiminny.atlassian.net/jira/software/c/projects/JY/boards/37
⏱ Timeline
...Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your
secondly
limit.","erro
… (click to expand)
▶ video
22 Apr 12:11
Screen
Firefox
/ SevenShores\Hubspot\Exceptions\BadRequest: Client
jiminny.sentry.io/issues/7007366572/events/?project=82419&referrer=slack
⏱ Timeline
...Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your
secondly
limit.","erro
… (click to expand)
▶ video
22 Apr 12:07
Screen
Firefox
/ Meet - CRM issues — Work
meet.google.com/pei-cvuh-fxt?authuser=lukas.kovalik%40jiminny.com
⏱ Timeline
...Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your
secondly
limit.","erro
… (click to expand)
▶ video
22 Apr 11:09
Screen
Firefox
/ Meet - CRM issues — Work
meet.google.com/pei-cvuh-fxt?authuser=lukas.kovalik%40jiminny.com
⏱ Timeline
...Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your
secondly
limit.","erro
… (click to expand)
▶ video
22 Apr 11:08
Screen
Firefox
/ Meet - CRM issues — Work
meet.google.com/pei-cvuh-fxt?authuser=lukas.kovalik%40jiminny.com
⏱ Timeline
...Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your
secondly
limit.","erro
… (click to expand)
▶ video
22 Apr 11:02
Screen
Firefox
/ Meet - CRM issues — Work
meet.google.com/pei-cvuh-fxt?authuser=lukas.kovalik%40jiminny.com
⏱ Timeline
...Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your
secondly
limit.","erro
… (click to expand)
▶ video
22 Apr 11:01
Screen
Firefox
/ Meet - CRM issues — Work
meet.google.com/pei-cvuh-fxt?authuser=lukas.kovalik%40jiminny.com
⏱ Timeline
...Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your
secondly
limit.","erro
… (click to expand)
22 Apr 11:00
Typed
clipboard
⏱ Timeline
...search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your
secondly
limit.","errorType":"RATE_LIMIT","correlationId":"019db2b6-c (truncated...)
▶ video
22 Apr 11:00
Screen
Firefox
/ SevenShores\Hubspot\Exceptions\BadRequest: Client
jiminny.sentry.io/issues/7007366572/events/38fa421c52fc432b92bfc347df23b251/
⏱ Timeline
...Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your
secondly
limit.","erro
… (click to expand)
▶ video
22 Apr 10:58
Screen
Firefox
/ SevenShores\Hubspot\Exceptions\BadRequest: Client
jiminny.sentry.io/issues/7007366572/?project=82419&referrer=slack
⏱ Timeline
...Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your
secondly
limit.","erro
… (click to expand)
✕
17:17 · Firefox
No screenshot or video available
FULL TEXT
=
⏱ Open in Timetable
METADATA
Time
17:17
Date
2026-05-07...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New Tab","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Screenpipe — Archive","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Screenpipe — Archive","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.043402776,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"bounds":{"left":0.06631944,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.08958333,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.112847224,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bitwarden","depth":6,"bounds":{"left":0.13611111,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Screenpipe [archive.db · 12323.6MB]","depth":7,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Screenpipe","depth":8,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"[archive.db · 12323.6MB]","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Activity","depth":7,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Search","depth":7,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Audio","depth":7,"on_screen":true,"help_text":"No audio data in this database","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Work Report","depth":7,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Timetable","depth":7,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Summary","depth":7,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Date","depth":8,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"07","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":8,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"05","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":8,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2026","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Calendar","depth":8,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"SECONDLY","depth":8,"on_screen":true,"value":"SECONDLY","help_text":"","role_description":"text field","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Search","depth":8,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AND also","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXTextField","text":"second required term — both must appear in same result (optional)","depth":8,"on_screen":true,"help_text":"","role_description":"text field","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Source","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"App","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Date","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"dd","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"mm","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"yyyy","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Calendar","depth":9,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"(blank = all dates)","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"From","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"--","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"--","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"To","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"--","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"--","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Only apps","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"any app (blank = all)","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"▾","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Skip apps","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"none skipped","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"▾","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"FTS tip: single words work best · \"exact phrase\" · term1 OR term2 · use AND also for required second term · times are in your local timezone · click any result to expand","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"49 results","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"▶ video","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"7 May 19:25","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Screen","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"PhpStorm","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/ faVsco.js – Client.php","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":true,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"...true) ??","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":SpolicyName = $body","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'policyName'","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"?? Sbody","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'policy'","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"?? null:Map pollcy names to retry delaysif (SpolicvName === 'TEN","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SECONDLY","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"_ROLLING' |I SpolicvName === 'ten","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"secondly","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"rolling') {","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"… (click to expand)","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"▶ video","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"7 May 19:10","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Screen","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"PhpStorm","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/ faVsco.js – Client.php","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":true,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"...true) ??","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":Snolievlane = Sbod/LUpoltiev/lane:1 22 Shody","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"LnolieyL1L.22 п11rao nolicy names to retry delav1f SpoLicvName ==='TEN","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SECONDLY","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ROLLING' |I SpolicvName === 'ten","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"secondly","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"rolling') {Le","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"… (click to expand)","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"7 May 17:24","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Typed","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"text","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":true,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":".","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"7 May 17:23","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Typed","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"text","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":true,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"7 May 17:22","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Typed","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"text","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":true,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":".","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"7 May 17:22","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Typed","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"text","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":true,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"'","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"7 May 17:21","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Typed","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"text","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":true,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"7 May 17:20","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Typed","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"text","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":true,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"7 May 17:19","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Typed","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"text","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":true,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"7 May 17:17","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Typed","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"text","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":true,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"7 May 17:17","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Typed","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"text","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":true,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"$","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"7 May 17:17","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Typed","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"text","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":true,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":";","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"7 May 17:17","depth":11,"bounds":{"left":0.48159721,"top":0.0,"width":0.042013887,"height":0.015},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Typed","depth":11,"bounds":{"left":0.53055555,"top":0.0,"width":0.01875,"height":0.012222222},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"bounds":{"left":0.5548611,"top":0.0,"width":0.02673611,"height":0.015},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"text","depth":11,"bounds":{"left":0.58368057,"top":0.0,"width":0.012847222,"height":0.013888889},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":true,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"=","depth":11,"bounds":{"left":0.48159721,"top":0.0,"width":0.0055555557,"height":0.017777778},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"7 May 17:16","depth":11,"bounds":{"left":0.48159721,"top":0.014444444,"width":0.04236111,"height":0.015},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Typed","depth":11,"bounds":{"left":0.5309028,"top":0.016666668,"width":0.01875,"height":0.012222222},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"bounds":{"left":0.5552083,"top":0.014444444,"width":0.027083334,"height":0.015},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"text","depth":11,"bounds":{"left":0.584375,"top":0.015555556,"width":0.012847222,"height":0.013888889},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":false,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":":","depth":11,"bounds":{"left":0.48159721,"top":0.04111111,"width":0.0027777778,"height":0.017777778},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"7 May 17:16","depth":11,"bounds":{"left":0.48159721,"top":0.093333334,"width":0.04236111,"height":0.015},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Typed","depth":11,"bounds":{"left":0.5309028,"top":0.09555556,"width":0.01875,"height":0.012222222},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"bounds":{"left":0.5552083,"top":0.093333334,"width":0.027083334,"height":0.015},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"text","depth":11,"bounds":{"left":0.584375,"top":0.094444446,"width":0.012847222,"height":0.013888889},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":false,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"7 May 17:15","depth":11,"bounds":{"left":0.48159721,"top":0.15055555,"width":0.04236111,"height":0.015},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Typed","depth":11,"bounds":{"left":0.5309028,"top":0.15277778,"width":0.01875,"height":0.012222222},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"bounds":{"left":0.5552083,"top":0.15055555,"width":0.02673611,"height":0.015},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"text","depth":11,"bounds":{"left":0.584375,"top":0.15166667,"width":0.0125,"height":0.013888889},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":false,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":".","depth":11,"bounds":{"left":0.48159721,"top":0.17722222,"width":0.0027777778,"height":0.017777778},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"7 May 17:15","depth":11,"bounds":{"left":0.48159721,"top":0.22944444,"width":0.04236111,"height":0.015},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Typed","depth":11,"bounds":{"left":0.5309028,"top":0.23166667,"width":0.01875,"height":0.012222222},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"bounds":{"left":0.5552083,"top":0.22944444,"width":0.02673611,"height":0.015},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"text","depth":11,"bounds":{"left":0.584375,"top":0.23055555,"width":0.0125,"height":0.013888889},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":false,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"7 May 17:14","depth":11,"bounds":{"left":0.48159721,"top":0.28666666,"width":0.04236111,"height":0.015},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Typed","depth":11,"bounds":{"left":0.5309028,"top":0.2888889,"width":0.01875,"height":0.012222222},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"bounds":{"left":0.5555556,"top":0.28666666,"width":0.02673611,"height":0.015},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"text","depth":11,"bounds":{"left":0.584375,"top":0.28777778,"width":0.012847222,"height":0.013888889},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":false,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"7 May 17:14","depth":11,"bounds":{"left":0.48159721,"top":0.34388888,"width":0.04236111,"height":0.015},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Typed","depth":11,"bounds":{"left":0.5309028,"top":0.34611112,"width":0.01875,"height":0.012222222},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"bounds":{"left":0.5555556,"top":0.34388888,"width":0.02673611,"height":0.015},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"text","depth":11,"bounds":{"left":0.584375,"top":0.345,"width":0.012847222,"height":0.013888889},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":false,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":".","depth":11,"bounds":{"left":0.48159721,"top":0.37055555,"width":0.0027777778,"height":0.017777778},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"7 May 17:10","depth":11,"bounds":{"left":0.48159721,"top":0.42277777,"width":0.04236111,"height":0.015},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Typed","depth":11,"bounds":{"left":0.5309028,"top":0.425,"width":0.01875,"height":0.012222222},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"bounds":{"left":0.5552083,"top":0.42277777,"width":0.027083334,"height":0.015},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"text","depth":11,"bounds":{"left":0.584375,"top":0.4238889,"width":0.012847222,"height":0.013888889},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":false,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"7 May 17:09","depth":11,"bounds":{"left":0.48159721,"top":0.48,"width":0.04375,"height":0.015},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Typed","depth":11,"bounds":{"left":0.53229165,"top":0.48222223,"width":0.01875,"height":0.012222222},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"bounds":{"left":0.55659723,"top":0.48,"width":0.02673611,"height":0.015},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"text","depth":11,"bounds":{"left":0.5857639,"top":0.4811111,"width":0.0125,"height":0.013888889},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":false,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"7 May 17:08","depth":11,"bounds":{"left":0.48159721,"top":0.5372222,"width":0.04375,"height":0.015},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Typed","depth":11,"bounds":{"left":0.53229165,"top":0.53944445,"width":0.01875,"height":0.012222222},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"bounds":{"left":0.55659723,"top":0.5372222,"width":0.02673611,"height":0.015},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"text","depth":11,"bounds":{"left":0.5857639,"top":0.53833336,"width":0.012847222,"height":0.013888889},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":false,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"7 May 17:07","depth":11,"bounds":{"left":0.48159721,"top":0.59444445,"width":0.043055557,"height":0.015},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Typed","depth":11,"bounds":{"left":0.5315972,"top":0.5966667,"width":0.01875,"height":0.012222222},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"bounds":{"left":0.5559028,"top":0.59444445,"width":0.02673611,"height":0.015},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"text","depth":11,"bounds":{"left":0.5850694,"top":0.59555554,"width":0.012847222,"height":0.013888889},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":false,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"7 May 14:13","depth":11,"bounds":{"left":0.48159721,"top":0.65166664,"width":0.043055557,"height":0.015},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Typed","depth":11,"bounds":{"left":0.5315972,"top":0.6538889,"width":0.01875,"height":0.012222222},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Claude","depth":12,"bounds":{"left":0.5559028,"top":0.65166664,"width":0.027083334,"height":0.015},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"text","depth":11,"bounds":{"left":0.5850694,"top":0.6527778,"width":0.012847222,"height":0.013888889},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":false,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"secondly","depth":12,"bounds":{"left":0.48229167,"top":0.67833334,"width":0.03784722,"height":0.017777778},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"7 May 10:58","depth":11,"bounds":{"left":0.48159721,"top":0.73055553,"width":0.044444446,"height":0.015},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Typed","depth":11,"bounds":{"left":0.5329861,"top":0.7327778,"width":0.01875,"height":0.012222222},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"clipboard","depth":11,"bounds":{"left":0.5572917,"top":0.7316667,"width":0.03125,"height":0.013888889},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":false,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"...search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your","depth":11,"bounds":{"left":0.48159721,"top":0.75722224,"width":0.47534722,"height":0.017777778},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"secondly","depth":12,"bounds":{"left":0.95763886,"top":0.75722224,"width":0.03784722,"height":0.017777778},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"limit.\",\"errorType\":\"RATE_LIMIT\",\"correlationId\":\"019dffc4-4 (truncated...)","depth":11,"bounds":{"left":0.99618053,"top":0.75722224,"width":0.0038194656,"height":0.017777778},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"7 May 10:41","depth":11,"bounds":{"left":0.48159721,"top":0.8094444,"width":0.043055557,"height":0.015},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Typed","depth":11,"bounds":{"left":0.5315972,"top":0.81166667,"width":0.01875,"height":0.012222222},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"clipboard","depth":11,"bounds":{"left":0.5559028,"top":0.8105556,"width":0.03125,"height":0.013888889},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":false,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"...search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your","depth":11,"bounds":{"left":0.48159721,"top":0.8361111,"width":0.47534722,"height":0.017777778},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"secondly","depth":12,"bounds":{"left":0.95763886,"top":0.8361111,"width":0.03784722,"height":0.017777778},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"limit.\",\"errorType\":\"RATE_LIMIT\",\"correlationId\":\"019dffc4-4 (truncated...)","depth":11,"bounds":{"left":0.99618053,"top":0.8361111,"width":0.0038194656,"height":0.017777778},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"7 May 10:41","depth":11,"bounds":{"left":0.48159721,"top":0.8883333,"width":0.043055557,"height":0.015},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Typed","depth":11,"bounds":{"left":0.5315972,"top":0.89055556,"width":0.01875,"height":0.012222222},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"bounds":{"left":0.5559028,"top":0.8883333,"width":0.02673611,"height":0.015},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"text","depth":11,"bounds":{"left":0.5847222,"top":0.8894445,"width":0.012847222,"height":0.013888889},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":false,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"7 May 10:41","depth":11,"bounds":{"left":0.48159721,"top":0.94555557,"width":0.043055557,"height":0.015},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Typed","depth":11,"bounds":{"left":0.5315972,"top":0.94777775,"width":0.01875,"height":0.012222222},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"bounds":{"left":0.5559028,"top":0.94555557,"width":0.02673611,"height":0.015},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"text","depth":11,"bounds":{"left":0.5847222,"top":0.94666666,"width":0.012847222,"height":0.013888889},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":false,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":")","depth":11,"bounds":{"left":0.48159721,"top":0.9722222,"width":0.0034722222,"height":0.017777778},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"7 May 10:41","depth":11,"bounds":{"left":0.48159721,"top":1.0,"width":0.043055557,"height":-0.02444446},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Typed","depth":11,"bounds":{"left":0.5315972,"top":1.0,"width":0.01875,"height":-0.026666641},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"bounds":{"left":0.5559028,"top":1.0,"width":0.02673611,"height":-0.02444446},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"text","depth":11,"bounds":{"left":0.5847222,"top":1.0,"width":0.012847222,"height":-0.02555561},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":false,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":",","depth":11,"bounds":{"left":0.48159721,"top":1.0,"width":0.0027777778,"height":-0.051111102},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"7 May 10:41","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Typed","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"text","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":false,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"(","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"7 May 10:38","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Typed","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"text","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":false,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"▶ video","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"22 Apr 12:58","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Screen","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/ Jiminny — Work","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app.staging.jiminny.com/ai-reports/pdf/582d4b50-8cd3-42a9-9819-d676ff8f3b43","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":false,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"...Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"secondly","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"limit.\",\"erro","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"… (click to expand)","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"▶ video","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"22 Apr 12:50","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Screen","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/ Pull requests · jiminny/app — Work","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"github.com/jiminny/app/pull/11998","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":false,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"...Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"secondly","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"limit.\",\"erro","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"… (click to expand)","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"▶ video","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"22 Apr 12:44","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Screen","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/ Platform Sprint 2 Q2 - Platform Team - Scrum Board","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"jiminny.atlassian.net/jira/software/c/projects/JY/boards/37","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":false,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"...Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"secondly","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"limit.\",\"erro","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"… (click to expand)","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"22 Apr 12:42","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Typed","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"clipboard","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":false,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"...search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"secondly","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"limit.\",\"errorType\":\"RATE_LIMIT\",\"correlationId\":\"019db2b6-c (truncated...)","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"▶ video","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"22 Apr 12:42","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Screen","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/ SevenShores\\Hubspot\\Exceptions\\BadRequest: Client","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"jiminny.sentry.io/issues/7007366572/events/38fa421c52fc432b92bfc347df23b251/","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":false,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"...Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"secondly","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"limit.\",\"erro","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"… (click to expand)","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"▶ video","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"22 Apr 12:41","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Screen","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/ SevenShores\\Hubspot\\Exceptions\\BadRequest: Client","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"jiminny.sentry.io/issues/7007366572/events/?project=82419&referrer=slack","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":false,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"...Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"secondly","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"limit.\",\"erro","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"… (click to expand)","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"▶ video","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"22 Apr 12:40","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Screen","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/ SevenShores\\Hubspot\\Exceptions\\BadRequest: Client","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"jiminny.sentry.io/issues/7007366572/events/?project=82419&referrer=slack","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":false,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"...Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"secondly","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"limit.\",\"erro","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"… (click to expand)","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"▶ video","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"22 Apr 12:39","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Screen","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/ Pipelines - /app — Work","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app.circleci.com/pipelines/github/jiminny/app","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":false,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"...Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"secondly","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"limit.\",\"erro","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"… (click to expand)","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"▶ video","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"22 Apr 12:20","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Screen","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/ Platform Sprint 2 Q2 - Platform Team - Scrum Board","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"jiminny.atlassian.net/jira/software/c/projects/JY/boards/37","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":false,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"...Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"secondly","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"limit.\",\"erro","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"… (click to expand)","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"▶ video","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"22 Apr 12:11","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Screen","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/ SevenShores\\Hubspot\\Exceptions\\BadRequest: Client","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"jiminny.sentry.io/issues/7007366572/events/?project=82419&referrer=slack","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":false,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"...Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"secondly","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"limit.\",\"erro","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"… (click to expand)","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"▶ video","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"22 Apr 12:07","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Screen","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/ Meet - CRM issues — Work","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"meet.google.com/pei-cvuh-fxt?authuser=lukas.kovalik%40jiminny.com","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":false,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"...Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"secondly","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"limit.\",\"erro","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"… (click to expand)","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"▶ video","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"22 Apr 11:09","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Screen","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/ Meet - CRM issues — Work","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"meet.google.com/pei-cvuh-fxt?authuser=lukas.kovalik%40jiminny.com","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":false,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"...Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"secondly","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"limit.\",\"erro","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"… (click to expand)","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"▶ video","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"22 Apr 11:08","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Screen","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/ Meet - CRM issues — Work","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"meet.google.com/pei-cvuh-fxt?authuser=lukas.kovalik%40jiminny.com","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":false,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"...Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"secondly","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"limit.\",\"erro","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"… (click to expand)","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"▶ video","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"22 Apr 11:02","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Screen","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/ Meet - CRM issues — Work","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"meet.google.com/pei-cvuh-fxt?authuser=lukas.kovalik%40jiminny.com","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":false,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"...Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"secondly","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"limit.\",\"erro","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"… (click to expand)","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"▶ video","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"22 Apr 11:01","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Screen","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/ Meet - CRM issues — Work","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"meet.google.com/pei-cvuh-fxt?authuser=lukas.kovalik%40jiminny.com","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":false,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"...Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"secondly","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"limit.\",\"erro","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"… (click to expand)","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"22 Apr 11:00","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Typed","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"clipboard","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":false,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"...search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"secondly","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"limit.\",\"errorType\":\"RATE_LIMIT\",\"correlationId\":\"019db2b6-c (truncated...)","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"▶ video","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"22 Apr 11:00","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Screen","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/ SevenShores\\Hubspot\\Exceptions\\BadRequest: Client","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"jiminny.sentry.io/issues/7007366572/events/38fa421c52fc432b92bfc347df23b251/","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":false,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"...Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"secondly","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"limit.\",\"erro","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"… (click to expand)","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"▶ video","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"22 Apr 10:58","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Screen","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/ SevenShores\\Hubspot\\Exceptions\\BadRequest: Client","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"jiminny.sentry.io/issues/7007366572/?project=82419&referrer=slack","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Timeline","depth":10,"on_screen":false,"help_text":"Open in Timetable","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"...Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"secondly","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"limit.\",\"erro","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"… (click to expand)","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"✕","depth":8,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"17:17 · Firefox","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"No screenshot or video available","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"FULL TEXT","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"=","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏱ Open in Timetable","depth":9,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"METADATA","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Time","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"17:17","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Date","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2026-05-07","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-8888658461309271959
|
6612526152100808961
|
click
|
accessibility
|
NULL
|
New Tab
New Tab
Screenpipe — Archive
Screenpipe — New Tab
New Tab
Screenpipe — Archive
Screenpipe — Archive
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Screenpipe [archive.db · 12323.6MB]
Screenpipe
[archive.db · 12323.6MB]
Activity
Search
Audio
Work Report
Timetable
AI Summary
Date
07
/
05
/
2026
Calendar
SECONDLY
Search
AND also
second required term — both must appear in same result (optional)
Source
App
Date
dd
/
mm
/
yyyy
Calendar
(blank = all dates)
From
--
:
--
To
--
:
--
Only apps
any app (blank = all)
▾
Skip apps
none skipped
▾
FTS tip: single words work best · "exact phrase" · term1 OR term2 · use AND also for required second term · times are in your local timezone · click any result to expand
49 results
▶ video
7 May 19:25
Screen
PhpStorm
/ faVsco.js – Client.php
⏱ Timeline
...true) ??
:SpolicyName = $body
'policyName'
?? Sbody
'policy'
?? null:Map pollcy names to retry delaysif (SpolicvName === 'TEN
SECONDLY
_ROLLING' |I SpolicvName === 'ten
secondly
rolling') {
… (click to expand)
▶ video
7 May 19:10
Screen
PhpStorm
/ faVsco.js – Client.php
⏱ Timeline
...true) ??
:Snolievlane = Sbod/LUpoltiev/lane:1 22 Shody
LnolieyL1L.22 п11rao nolicy names to retry delav1f SpoLicvName ==='TEN
SECONDLY
ROLLING' |I SpolicvName === 'ten
secondly
rolling') {Le
… (click to expand)
7 May 17:24
Typed
Firefox
text
⏱ Timeline
.
7 May 17:23
Typed
Firefox
text
⏱ Timeline
7 May 17:22
Typed
Firefox
text
⏱ Timeline
.
7 May 17:22
Typed
Firefox
text
⏱ Timeline
'
7 May 17:21
Typed
Firefox
text
⏱ Timeline
7 May 17:20
Typed
Firefox
text
⏱ Timeline
7 May 17:19
Typed
Firefox
text
⏱ Timeline
7 May 17:17
Typed
Firefox
text
⏱ Timeline
7 May 17:17
Typed
Firefox
text
⏱ Timeline
$
7 May 17:17
Typed
Firefox
text
⏱ Timeline
;
7 May 17:17
Typed
Firefox
text
⏱ Timeline
=
7 May 17:16
Typed
Firefox
text
⏱ Timeline
:
7 May 17:16
Typed
Firefox
text
⏱ Timeline
7 May 17:15
Typed
Firefox
text
⏱ Timeline
.
7 May 17:15
Typed
Firefox
text
⏱ Timeline
7 May 17:14
Typed
Firefox
text
⏱ Timeline
7 May 17:14
Typed
Firefox
text
⏱ Timeline
.
7 May 17:10
Typed
Firefox
text
⏱ Timeline
7 May 17:09
Typed
Firefox
text
⏱ Timeline
7 May 17:08
Typed
Firefox
text
⏱ Timeline
7 May 17:07
Typed
Firefox
text
⏱ Timeline
7 May 14:13
Typed
Claude
text
⏱ Timeline
secondly
7 May 10:58
Typed
clipboard
⏱ Timeline
...search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your
secondly
limit.","errorType":"RATE_LIMIT","correlationId":"019dffc4-4 (truncated...)
7 May 10:41
Typed
clipboard
⏱ Timeline
...search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your
secondly
limit.","errorType":"RATE_LIMIT","correlationId":"019dffc4-4 (truncated...)
7 May 10:41
Typed
Firefox
text
⏱ Timeline
7 May 10:41
Typed
Firefox
text
⏱ Timeline
)
7 May 10:41
Typed
Firefox
text
⏱ Timeline
,
7 May 10:41
Typed
Firefox
text
⏱ Timeline
(
7 May 10:38
Typed
Firefox
text
⏱ Timeline
▶ video
22 Apr 12:58
Screen
Firefox
/ Jiminny — Work
app.staging.jiminny.com/ai-reports/pdf/582d4b50-8cd3-42a9-9819-d676ff8f3b43
⏱ Timeline
...Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your
secondly
limit.","erro
… (click to expand)
▶ video
22 Apr 12:50
Screen
Firefox
/ Pull requests · jiminny/app — Work
github.com/jiminny/app/pull/11998
⏱ Timeline
...Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your
secondly
limit.","erro
… (click to expand)
▶ video
22 Apr 12:44
Screen
Firefox
/ Platform Sprint 2 Q2 - Platform Team - Scrum Board
jiminny.atlassian.net/jira/software/c/projects/JY/boards/37
⏱ Timeline
...Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your
secondly
limit.","erro
… (click to expand)
22 Apr 12:42
Typed
clipboard
⏱ Timeline
...search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your
secondly
limit.","errorType":"RATE_LIMIT","correlationId":"019db2b6-c (truncated...)
▶ video
22 Apr 12:42
Screen
Firefox
/ SevenShores\Hubspot\Exceptions\BadRequest: Client
jiminny.sentry.io/issues/7007366572/events/38fa421c52fc432b92bfc347df23b251/
⏱ Timeline
...Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your
secondly
limit.","erro
… (click to expand)
▶ video
22 Apr 12:41
Screen
Firefox
/ SevenShores\Hubspot\Exceptions\BadRequest: Client
jiminny.sentry.io/issues/7007366572/events/?project=82419&referrer=slack
⏱ Timeline
...Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your
secondly
limit.","erro
… (click to expand)
▶ video
22 Apr 12:40
Screen
Firefox
/ SevenShores\Hubspot\Exceptions\BadRequest: Client
jiminny.sentry.io/issues/7007366572/events/?project=82419&referrer=slack
⏱ Timeline
...Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your
secondly
limit.","erro
… (click to expand)
▶ video
22 Apr 12:39
Screen
Firefox
/ Pipelines - /app — Work
app.circleci.com/pipelines/github/jiminny/app
⏱ Timeline
...Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your
secondly
limit.","erro
… (click to expand)
▶ video
22 Apr 12:20
Screen
Firefox
/ Platform Sprint 2 Q2 - Platform Team - Scrum Board
jiminny.atlassian.net/jira/software/c/projects/JY/boards/37
⏱ Timeline
...Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your
secondly
limit.","erro
… (click to expand)
▶ video
22 Apr 12:11
Screen
Firefox
/ SevenShores\Hubspot\Exceptions\BadRequest: Client
jiminny.sentry.io/issues/7007366572/events/?project=82419&referrer=slack
⏱ Timeline
...Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your
secondly
limit.","erro
… (click to expand)
▶ video
22 Apr 12:07
Screen
Firefox
/ Meet - CRM issues — Work
meet.google.com/pei-cvuh-fxt?authuser=lukas.kovalik%40jiminny.com
⏱ Timeline
...Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your
secondly
limit.","erro
… (click to expand)
▶ video
22 Apr 11:09
Screen
Firefox
/ Meet - CRM issues — Work
meet.google.com/pei-cvuh-fxt?authuser=lukas.kovalik%40jiminny.com
⏱ Timeline
...Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your
secondly
limit.","erro
… (click to expand)
▶ video
22 Apr 11:08
Screen
Firefox
/ Meet - CRM issues — Work
meet.google.com/pei-cvuh-fxt?authuser=lukas.kovalik%40jiminny.com
⏱ Timeline
...Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your
secondly
limit.","erro
… (click to expand)
▶ video
22 Apr 11:02
Screen
Firefox
/ Meet - CRM issues — Work
meet.google.com/pei-cvuh-fxt?authuser=lukas.kovalik%40jiminny.com
⏱ Timeline
...Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your
secondly
limit.","erro
… (click to expand)
▶ video
22 Apr 11:01
Screen
Firefox
/ Meet - CRM issues — Work
meet.google.com/pei-cvuh-fxt?authuser=lukas.kovalik%40jiminny.com
⏱ Timeline
...Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your
secondly
limit.","erro
… (click to expand)
22 Apr 11:00
Typed
clipboard
⏱ Timeline
...search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your
secondly
limit.","errorType":"RATE_LIMIT","correlationId":"019db2b6-c (truncated...)
▶ video
22 Apr 11:00
Screen
Firefox
/ SevenShores\Hubspot\Exceptions\BadRequest: Client
jiminny.sentry.io/issues/7007366572/events/38fa421c52fc432b92bfc347df23b251/
⏱ Timeline
...Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your
secondly
limit.","erro
… (click to expand)
▶ video
22 Apr 10:58
Screen
Firefox
/ SevenShores\Hubspot\Exceptions\BadRequest: Client
jiminny.sentry.io/issues/7007366572/?project=82419&referrer=slack
⏱ Timeline
...Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your
secondly
limit.","erro
… (click to expand)
✕
17:17 · Firefox
No screenshot or video available
FULL TEXT
=
⏱ Open in Timetable
METADATA
Time
17:17
Date
2026-05-07...
|
17494
|
NULL
|
NULL
|
NULL
|
|
17712
|
777
|
43
|
2026-05-11T10:30:25.577152+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778495425577_m2.jpg...
|
Firefox
|
Screenpipe — Archive — Personal
|
True
|
app.screenpipe.lakylak.xyz
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
New Tab
New Tab
Screenpipe — Archive
Screenpipe — New Tab
New Tab
Screenpipe — Archive
Screenpipe — Archive
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Screenpipe [archive.db · 12323.6MB]
Screenpipe
[archive.db · 12323.6MB]
Activity
Search
Audio
Work Report
Timetable
AI Summary
Date
07
/
05
/
2026
Calendar
Monitor
Jump to
--
:
--
Go
APP TIMELINE · CLICK TO PLAY · DRAG SCROLLBAR TO PAN
−
1×
+
Follow
Follow
10:00
10:30
11:00
11:30
12:00
12:30
13:00
13:30
14:00
14:30
15:00
15:30
16:00
16:30
17:00
17:30
18:00
18:30
19:00
19:30
20:00
20:30
21:00
21:30
7 May 15:34 · PhpStorm / faVsco.js – laravel.log
⏮ 30s
◀ 10s
⏸ Pause
10s ▶
30s ⏭
15:34
iTerm2
Firefox
CleanShot X
Finder
QuickTime Player
PhpStorm
Music
Control Centre
Claude
Slack
Alfred
Raycast
System Information...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"New Tab","depth":4,"bounds":{"left":0.2942154,"top":0.0518755,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New Tab","depth":5,"bounds":{"left":0.3075133,"top":0.06304868,"width":0.014960106,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Screenpipe — Archive","depth":4,"bounds":{"left":0.2942154,"top":0.08459697,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Screenpipe — Archive","depth":5,"bounds":{"left":0.3075133,"top":0.09577015,"width":0.037898935,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.3956117,"top":0.09177973,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.29704124,"top":0.118914604,"width":0.108211435,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.29704124,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"bounds":{"left":0.30801198,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.31914893,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.3302859,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bitwarden","depth":6,"bounds":{"left":0.3414229,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Screenpipe [archive.db · 12323.6MB]","depth":7,"bounds":{"left":0.41456118,"top":0.061452515,"width":0.06698803,"height":0.017956903},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Screenpipe","depth":8,"bounds":{"left":0.41456118,"top":0.06304868,"width":0.027759308,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"[archive.db · 12323.6MB]","depth":9,"bounds":{"left":0.44365028,"top":0.06703911,"width":0.037898935,"height":0.009976057},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Activity","depth":7,"bounds":{"left":0.48620346,"top":0.059856344,"width":0.024767287,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Search","depth":7,"bounds":{"left":0.51163566,"top":0.059856344,"width":0.023769947,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Audio","depth":7,"bounds":{"left":0.53607047,"top":0.059856344,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"No audio data in this database","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Work Report","depth":7,"bounds":{"left":0.55767953,"top":0.059856344,"width":0.03507314,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Timetable","depth":7,"bounds":{"left":0.5934175,"top":0.059856344,"width":0.029753989,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Summary","depth":7,"bounds":{"left":0.62383646,"top":0.059856344,"width":0.034075797,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Date","depth":8,"bounds":{"left":0.93849736,"top":0.0650439,"width":0.008144947,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"07","depth":9,"bounds":{"left":0.9552859,"top":0.06464485,"width":0.0048204786,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":8,"bounds":{"left":0.96110374,"top":0.06464485,"width":0.0023271276,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"05","depth":9,"bounds":{"left":0.9644282,"top":0.06464485,"width":0.0048204786,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":8,"bounds":{"left":0.970246,"top":0.06464485,"width":0.002493351,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2026","depth":9,"bounds":{"left":0.9737367,"top":0.06464485,"width":0.009474734,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Calendar","depth":8,"bounds":{"left":0.98454124,"top":0.0650439,"width":0.0051529254,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Monitor","depth":9,"bounds":{"left":0.4945146,"top":0.10853951,"width":0.013464096,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Jump to","depth":9,"bounds":{"left":0.8530585,"top":0.10853951,"width":0.01412899,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"--","depth":10,"bounds":{"left":0.87317157,"top":0.10814046,"width":0.0048204786,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":9,"bounds":{"left":0.87898934,"top":0.10814046,"width":0.0023271276,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"--","depth":10,"bounds":{"left":0.88231385,"top":0.10814046,"width":0.0048204786,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Go","depth":8,"bounds":{"left":0.90109706,"top":0.10454908,"width":0.012300532,"height":0.018754989},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"APP TIMELINE · CLICK TO PLAY · DRAG SCROLLBAR TO PAN","depth":10,"bounds":{"left":0.49950132,"top":0.14964086,"width":0.10571808,"height":0.009976057},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"−","depth":9,"bounds":{"left":0.8558843,"top":0.1452514,"width":0.009807181,"height":0.018754989},"on_screen":true,"help_text":"Zoom out","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1×","depth":10,"bounds":{"left":0.86984706,"top":0.14924182,"width":0.004155585,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"+","depth":9,"bounds":{"left":0.87832445,"top":0.1452514,"width":0.009640957,"height":0.018754989},"on_screen":true,"help_text":"Zoom in","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Follow","depth":10,"bounds":{"left":0.8912899,"top":0.14924182,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Follow","depth":10,"bounds":{"left":0.89727396,"top":0.14924182,"width":0.011136968,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"10:00","depth":13,"bounds":{"left":0.50482047,"top":0.21947326,"width":0.008144947,"height":0.008778931},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"10:30","depth":13,"bounds":{"left":0.5219415,"top":0.21947326,"width":0.008144947,"height":0.008778931},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"11:00","depth":13,"bounds":{"left":0.539395,"top":0.21947326,"width":0.0076462766,"height":0.008778931},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"11:30","depth":13,"bounds":{"left":0.55651593,"top":0.21947326,"width":0.0076462766,"height":0.008778931},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"12:00","depth":13,"bounds":{"left":0.5734708,"top":0.21947326,"width":0.008144947,"height":0.008778931},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"12:30","depth":13,"bounds":{"left":0.5905917,"top":0.21947326,"width":0.008144947,"height":0.008778931},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"13:00","depth":13,"bounds":{"left":0.607879,"top":0.21947326,"width":0.008144947,"height":0.008778931},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"13:30","depth":13,"bounds":{"left":0.625,"top":0.21947326,"width":0.008144947,"height":0.008778931},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"14:00","depth":13,"bounds":{"left":0.642121,"top":0.21947326,"width":0.00831117,"height":0.008778931},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"14:30","depth":13,"bounds":{"left":0.65924203,"top":0.21947326,"width":0.00831117,"height":0.008778931},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"15:00","depth":13,"bounds":{"left":0.6765292,"top":0.21947326,"width":0.008144947,"height":0.008778931},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"15:30","depth":13,"bounds":{"left":0.69365025,"top":0.21947326,"width":0.008144947,"height":0.008778931},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"16:00","depth":13,"bounds":{"left":0.71077126,"top":0.21947326,"width":0.00831117,"height":0.008778931},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"16:30","depth":13,"bounds":{"left":0.7280585,"top":0.21947326,"width":0.008144947,"height":0.008778931},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"17:00","depth":13,"bounds":{"left":0.7453458,"top":0.21947326,"width":0.007978723,"height":0.008778931},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"17:30","depth":13,"bounds":{"left":0.7624667,"top":0.21947326,"width":0.007978723,"height":0.008778931},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"18:00","depth":13,"bounds":{"left":0.77958775,"top":0.21947326,"width":0.008144947,"height":0.008778931},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"18:30","depth":13,"bounds":{"left":0.79670876,"top":0.21947326,"width":0.008144947,"height":0.008778931},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"19:00","depth":13,"bounds":{"left":0.8138298,"top":0.21947326,"width":0.00831117,"height":0.008778931},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"19:30","depth":13,"bounds":{"left":0.83111703,"top":0.21947326,"width":0.008144947,"height":0.008778931},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"20:00","depth":13,"bounds":{"left":0.8479056,"top":0.21947326,"width":0.008643617,"height":0.008778931},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"20:30","depth":13,"bounds":{"left":0.86519283,"top":0.21947326,"width":0.008643617,"height":0.008778931},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"21:00","depth":13,"bounds":{"left":0.88248,"top":0.21947326,"width":0.008144947,"height":0.008778931},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"21:30","depth":13,"bounds":{"left":0.8997673,"top":0.21947326,"width":0.008144947,"height":0.008778931},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"7 May 15:34 · PhpStorm / faVsco.js – laravel.log","depth":10,"bounds":{"left":0.49817154,"top":0.2661612,"width":0.08892952,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏮ 30s","depth":9,"bounds":{"left":0.49883643,"top":0.7186752,"width":0.023936171,"height":0.02434158},"on_screen":true,"help_text":"Ctrl+←","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"◀ 10s","depth":9,"bounds":{"left":0.52543217,"top":0.71907425,"width":0.02244016,"height":0.023942538},"on_screen":true,"help_text":"←","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"⏸ Pause","depth":9,"bounds":{"left":0.5505319,"top":0.7186752,"width":0.027925532,"height":0.02434158},"on_screen":true,"help_text":"Space","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":true,"is_selected":false},{"role":"AXButton","text":"10s ▶","depth":9,"bounds":{"left":0.58111703,"top":0.71907425,"width":0.022273935,"height":0.023942538},"on_screen":true,"help_text":"→","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"30s ⏭","depth":9,"bounds":{"left":0.60605055,"top":0.7186752,"width":0.024102394,"height":0.02434158},"on_screen":true,"help_text":"Ctrl+→","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"15:34","depth":10,"bounds":{"left":0.8992686,"top":0.7254589,"width":0.009807181,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"iTerm2","depth":9,"bounds":{"left":0.49950132,"top":0.7609737,"width":0.011801862,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":9,"bounds":{"left":0.51961434,"top":0.7609737,"width":0.011801862,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"CleanShot X","depth":9,"bounds":{"left":0.5397274,"top":0.7609737,"width":0.021609042,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Finder","depth":9,"bounds":{"left":0.5696476,"top":0.7609737,"width":0.010970744,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"QuickTime Player","depth":9,"bounds":{"left":0.58892953,"top":0.7609737,"width":0.030086435,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"PhpStorm","depth":9,"bounds":{"left":0.62732714,"top":0.7609737,"width":0.017287234,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Music","depth":9,"bounds":{"left":0.65292555,"top":0.7609737,"width":0.010305851,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Control Centre","depth":9,"bounds":{"left":0.6715425,"top":0.7609737,"width":0.025598405,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Claude","depth":9,"bounds":{"left":0.70545214,"top":0.7609737,"width":0.012134309,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Slack","depth":9,"bounds":{"left":0.7258976,"top":0.7609737,"width":0.009474734,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Alfred","depth":9,"bounds":{"left":0.7436835,"top":0.7609737,"width":0.010472074,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Raycast","depth":9,"bounds":{"left":0.7624667,"top":0.7609737,"width":0.013630319,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"System Information","depth":9,"bounds":{"left":0.7844083,"top":0.7609737,"width":0.033909574,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
80815132705226152
|
2761186138836534169
|
visual_change
|
accessibility
|
NULL
|
New Tab
New Tab
Screenpipe — Archive
Screenpipe — New Tab
New Tab
Screenpipe — Archive
Screenpipe — Archive
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Screenpipe [archive.db · 12323.6MB]
Screenpipe
[archive.db · 12323.6MB]
Activity
Search
Audio
Work Report
Timetable
AI Summary
Date
07
/
05
/
2026
Calendar
Monitor
Jump to
--
:
--
Go
APP TIMELINE · CLICK TO PLAY · DRAG SCROLLBAR TO PAN
−
1×
+
Follow
Follow
10:00
10:30
11:00
11:30
12:00
12:30
13:00
13:30
14:00
14:30
15:00
15:30
16:00
16:30
17:00
17:30
18:00
18:30
19:00
19:30
20:00
20:30
21:00
21:30
7 May 15:34 · PhpStorm / faVsco.js – laravel.log
⏮ 30s
◀ 10s
⏸ Pause
10s ▶
30s ⏭
15:34
iTerm2
Firefox
CleanShot X
Finder
QuickTime Player
PhpStorm
Music
Control Centre
Claude
Slack
Alfred
Raycast
System Information...
|
NULL
|
NULL
|
NULL
|
NULL
|