Zodiac Tech CRM Docs

Mobile, developer & deployment FAQ

Technical answers about the Android app, Firebase without google-services.json, queues and cron on cPanel, tenant isolation, API access, updates and backups.

developer super-admin support Medium ⏱ 10 min Updated 2026-10-05

Mobile, developer & deployment FAQ

The technical questions developers, integrators and operators ask most — with the real file, command and permission names.

Mobile app

Does the Android app need a google-services.json file?

No — deliberately not. The app ships without one. At login it fetches the workspace's Firebase options from the CRM's mobile endpoints (auth-config / otp/start), caches them securely on the device, initializes Firebase at runtime, and only then requests an FCM token. That is what makes per-workspace "bring your own Firebase" possible without shipping per-client builds. See Firebase phone OTP.

Which Android versions and package does the app target?

Application ID com.zodiactech.crm (demo flavor com.zodiactech.crm.demo; the internal Kotlin namespace remains com.leadhub.sales and appears only in code class paths); minSdk 26 (Android 8.0), targetSdk 35; current version 1.0.0 (versionCode 1). Firebase phone auth must be registered with exactly this application ID plus your signing SHA-1. See Installation.

Why is the app sideloaded instead of published on Google Play?

The app uses the call log permission (READ_CALL_LOG) to match phone calls to CRM leads — a permission Google restricts for Play distribution. The current distribution model is sideload/MDM (e.g. for sales teams provisioned centrally). A demo APK exists for UI review: Demo APK.

How do deep links into the app work?

Push notifications and taps use crm:// URIs that the app resolves to screens: crm://lead/{id}, crm://call/{id}, crm://followup/{id}, crm://appointment/{id}, crm://notification/{id}. The server only attaches a deep link when the payload carries the matching entity id. See Push notifications.

How long do mobile sessions last, and how are device tokens secured?

Device tokens use Authorization: Bearer against /api/v1/mobile/..., have a 90-day TTL, and are stored hashed at rest (DeviceToken::hashToken) — the raw token is shown once to the device. Expired tokens require re-login. See Mobile API (device tokens).

Is FCM push required for the mobile app to work?

No — push is optional and best-effort. Without it, users see in-app notifications on next open. To enable push you configure a Firebase service account JSON server-side (encrypted setting or FCM_SERVICE_ACCOUNT_JSON); the app never needs a file. Every send swallows errors so push problems never block core flows. See Push notifications (FCM).

Queues, cron & deployment

What must run in production for the queue and scheduler?

Set QUEUE_CONNECTION=database and run a worker that covers all named queues — a bare queue:work only drains default and the others silently stall:

php artisan queue:work --queue=default,webhooks,automations,integrations,notifications,exports,ai-sdr,mail

And drive the scheduler every minute:

* * * * * cd /path/to/app && php artisan schedule:run >> /dev/null 2>&1

The scheduler carries WhatsApp/inbox sweeps (every 5 min), calendar sync (15 min), billing lifecycle, report delivery and backups. Local installs use QUEUE_CONNECTION=sync (everything inline) — do not ship that to production. Full guide: Cron & queue workers.

This is on shared cPanel hosting — I can't keep a worker process alive. What's the supported approach?

The product ships a single-cron runner for exactly this: point one cron job at the project's root cron.php every minute, and each invocation processes queued jobs and runs the due scheduler tasks:

* * * * * php /home/yourusername/public_html/cron.php >> /dev/null 2>&1

It processes up to 30 jobs plus scheduler work per minute and is protected from web execution by the CRON_SECRET token — see cPanel deployment walkthrough and Cron & queue workers.

How do I update a production install?

Super Admin → Updates page runs the updater (UpdaterService) with an update check. Take a backup first — the update flow assumes you have one. Walkthrough: Updates & rollback.

How do backups work here?

php artisan leadhub:backup {--prune=N} creates a database + files archive. If the operator has enabled the nightly toggle in Script Settings (General settings), it also runs automatically at 02:00. Super Admin → Backups creates on-demand archives and lists/downloads existing ones. Verify restores occasionally, not just backups: Backups & restore.

How is tenant isolation enforced in code?

Every tenant-owned model uses the BelongsToTenant global scope on tenant_id — fail-closed: with no tenant bound, queries return nothing rather than everything. The Super Admin panel operates by explicitly binding the internal "LeadHub HQ" workspace (BindHqTenant, marker settings.internal.crm_hq), so platform screens cannot leak tenant rows by accident. Read: Multi-tenancy & isolation.

API & sandboxing

How do I explore and test the APIs?
  • Interactive OpenAPI viewer: /api/docs.
  • REST API (API keys): Authorization: Bearer <key> against /api/v1/...; probe /api/v1/health. See REST API (API keys) and Authentication.
  • Mobile API (device tokens): /api/v1/mobile/...; auth-config is reachable pre-login by design. See Mobile API.
  • Errors share a documented envelope — Error codes & handling.
Is there a safe demo/sandbox mode?

Two separate things share the name "demo":

  • Platform demo mode (LEADHUB_DEMO_MODE): a lockdown that blocks destructive operations, credential saving and outbound communications — used for hosted demos.
  • Android offline demo mode: a button on the app's login screen that opens the app with bundled fixture data and no server.

Neither should be used to test real campaigns; see Demo APK and Mobile login.

Can I verify integrations from the command line?

Yes — the operator toolbox includes health checks and maintenance commands, e.g. php artisan leadhub:test-push {email} for push, leadhub:meta-health for Meta connectivity, leadhub:sync-calendars for calendar sync, and leadhub:backup for on-demand backups. For scheduled audits: Daily checks.

Something is broken on the server — where do I start?

Symptoms are mapped to causes in Deployment & server errors: queue not running, cron missing, mail falling into the log mailer, or webhook signatures failing. Check the Laravel log, the queue backlog and the scheduler output first — those three cover most incidents.

Was this page helpful?