Skip to content
Pages

Platform

Technical integrations

Every outside service the Leitagu apps and their hosting depend on, what each is used for, which app uses it, its settings, endpoints, code and what happens when it fails.

Updated 23 October 2026View as Markdown

Leitagu depends on few outside services. The apps talk to Anthropic (Claude, optional), Resend (account emails), Migadu (the CRM's shared mailbox) and the stores' own shops (Shopify, WooCommerce, feeds). The hosting uses GitHub Actions and GitHub Container Registry to build, Coolify on a DigitalOcean droplet to run, and Cloudflare R2 for backups; the domain and its DNS are at zone.ee. There is no outside analytics, maps, payment, SMS or file storage service. This page lists each integration as the code shows it; settings are named, never their values.

Summary

Integration What Leitagu uses it for App Settings
Anthropic (Claude) Reading typed chat messages and room photos Shop ANTHROPIC_API_KEY or ANTHROPIC_AUTH_TOKEN
Resend Verification, password-reset and staff invite emails Shop, admin RESEND_API_KEY, EMAIL_FROM, EMAIL_REPLY_TO, APP_URL
Migadu The CRM's shared partner mailbox (IMAP and SMTP) CRM CRM_MAIL_ADDRESS, CRM_MAIL_PASSWORD, CRM_MAIL_NAME, CRM_IMAP_HOST, CRM_IMAP_PORT, CRM_SMTP_HOST, CRM_SMTP_PORT, CRON_SECRET
Shopify Importing a store's products Partner (and admin MCP tools) INTEGRATION_SECRET_KEY, SHOPIFY_API_VERSION, CRON_SECRET
WooCommerce Importing a store's products Partner (and admin MCP tools) CRON_SECRET
Product feeds and CSV Importing a store's products Partner (and admin MCP tools) CRON_SECRET
Store websites Proving a store sign-up with a meta tag Partner None
AI assistant clients Claude and other MCP clients connecting to the staff tools Admin ADMIN_URL
Estonian business register A link from a CRM company to its register entry CRM None
Coolify on DigitalOcean Running the apps and the database All COOLIFY_DEPLOY_TOKEN (GitHub secret)
GitHub Actions and ghcr.io Building, checking and storing the app images All GITHUB_TOKEN (built in)
Cloudflare R2 Off-site backups Database, Coolify Kept in Coolify, not in the repository
zone.ee (domain and DNS) Registering leitagu.ee and its DNS records All None

CRON_SECRET protects Leitagu's own scheduled endpoints, not an outside service; it is listed where an integration is driven by one.

Services the apps call

Anthropic (Claude)

  • What. Anthropic's API, through the official SDK (@anthropic-ai/sdk).
  • Used for. Turning a shopper's typed message into search parameters, and reading a room photo (size, colours, openings and furniture) to build a room. Search, ranking and replies are Leitagu's own code; Claude only reads the input. See How the shop answers a chat.
  • App. Shop (apps/web).
  • Settings. ANTHROPIC_API_KEY, or ANTHROPIC_AUTH_TOKEN. Optional: without either, Claude is off.
  • Code. apps/web/src/lib/server/llm.ts (the model and the prompts), used by the chat page and POST /api/rooms/photo (apps/web/src/app/api/rooms/photo/route.ts).
  • When it fails. Without a key, chat messages are read by the keyword parser (packages/core/src/shared/parse.ts) and the photo route answers 503 (photo_needs_key), so the shop offers a room template instead. An API error or a refusal also falls back to the keyword parser; a photo that can't be read answers 422 (photo_fail). Photos are limited to 20 per person per hour, counted in memory per server.

Resend

  • What. Resend's email API, called directly at https://api.resend.com/emails (no SDK).
  • Used for. Email verification and password-reset emails for shoppers, and staff invite emails, in Estonian and English. Sent from Leitagu <noreply@leitagu.ee> unless EMAIL_FROM says otherwise; the sending domain must be verified in Resend.
  • Apps. Shop and admin.
  • Settings. RESEND_API_KEY; optional EMAIL_FROM, EMAIL_REPLY_TO; APP_URL (or WEB_URL) for the links.
  • Code. packages/core/src/server/mail.ts (sendMail), templates in packages/core/src/server/mailTemplates.ts.
  • When it fails. Sending never throws: a rejection, a timeout (10 seconds) or a network error is logged as [mail] … and reported as not sent, so signup and invites carry on. Without a key, links are printed to the console in development and nothing is sent in production, so new shoppers can't confirm their address; the admin app still shows each staff invite link to pass on by hand. Leitagu doesn't receive any webhooks from Resend.

Migadu

  • What. Migadu, the mail host of the team's shared partner mailbox (leitagu@partner.ee). The CRM uses it over standard IMAP and SMTP (imapflow, mailparser, nodemailer), not through an API, so any IMAP/SMTP host works; Migadu's servers are only the defaults.
  • Used for. Copying every email in the inbox and the Sent folder into the CRM, and sending emails from a company's page. See Email in the CRM page.
  • App. CRM.
  • Settings. CRM_MAIL_ADDRESS and CRM_MAIL_PASSWORD (both needed to connect); optional CRM_MAIL_NAME (default Leitagu), CRM_IMAP_HOST and CRM_IMAP_PORT (default imap.migadu.com, 993), CRM_SMTP_HOST and CRM_SMTP_PORT (default smtp.migadu.com, 465); CRON_SECRET for the scheduled read.
  • Endpoint. POST /api/cron/mail on the CRM (GET also works), with Authorization: Bearer and CRON_SECRET, every five minutes (see Scheduled jobs). It answers 401 without the right secret and 409 when the mailbox isn't connected.
  • Code. packages/core/src/server/crmMail.ts; apps/crm/src/app/api/cron/mail/route.ts.
  • When it fails. A folder that can't be read records its error in crm_mail_state, which the CRM shows next to "Last checked"; the other folder is still read. A failed send answers send_failed and nothing is saved. Without the settings, the CRM says the mailbox isn't connected.

Shopify

  • What. The Shopify Admin GraphQL API of each store that connects its Shopify shop, at https://<shop>.myshopify.com/admin/api/<version>/graphql.json.
  • Used for. Importing the store's products, on a schedule or when asked.
  • Apps. Partner app (data connections), and the admin app's MCP tools for staff who set up stores.
  • Settings. INTEGRATION_SECRET_KEY encrypts each store's access token (required in production; if it changes, stores must reconnect). Optional SHOPIFY_API_VERSION (default 2026-07).
  • Code. packages/core/src/server/integrations/fetchers.ts (fetchShopify, testShopify), sources.ts (mapping), secrets.ts (encryption), sync.ts (the run).
  • Details for stores. Shopify in the partner integrations guide.

WooCommerce

  • What. The public WooCommerce Store API of each connected shop (/wp-json/wc/store/v1/products). No key is needed.
  • Used for. Importing the store's products. Leitagu reads the shop's robots.txt first and follows it, including its crawl delay.
  • Apps. Partner app, and the admin app's MCP tools.
  • Code. packages/core/src/server/integrations/fetchers.ts (fetchWooCommerce, wooRobots), robots.ts, sources.ts.
  • Details for stores. WooCommerce.

Product feeds and CSV

  • What. A feed file at an address the store gives (a Google Merchant Center XML feed, or CSV/TSV), or a CSV file uploaded in the partner app.
  • Used for. Importing the store's products.
  • Apps. Partner app, and the admin app's MCP tools.
  • Code. packages/core/src/server/integrations/sources.ts (parseFeed, csvToItems), fetched with safeFetchText() in fetchers.ts.
  • Details for stores. Product feed and CSV upload.

For all store connections.

  • Endpoint. POST /api/cron/sync on the partner app (GET also works), with Authorization: Bearer and CRON_SECRET, every hour; it runs every Shopify, WooCommerce and feed connection that is due. The product pipeline backfill is POST /api/cron/pipeline with the same secret. How each runs in production is in Scheduled jobs.
  • Fetch safety. Addresses that stores give us are fetched only through safeFetch() / safeFetchText(): public addresses only (checked when connecting), checked redirects, size and time limits. See Feed fetch safety.
  • When a sync fails. The run is recorded in sync_runs as failed or partial with its error and issues, which the partner and admin apps show. One failing connection doesn't stop the others. Products are never hidden automatically when data gets old; staff decide (see Out-of-date data).

Store websites (sign-up proof)

  • What. The home page of a store that signs up in the partner app.
  • Used for. One of the ways to prove a store sign-up: Leitagu fetches the home page and looks for a meta tag with the claim's code. The other ways are an email address on the store's domain or staff approval.
  • App. Partner (/join); claims are approved in admin.
  • Code. packages/core/src/server/storeClaims.ts, packages/core/src/shared/storeClaims.ts. See How a store joins.

AI assistant clients (MCP)

  • What. The admin app is an MCP server and an OAuth 2.1 authorization server for AI assistants such as Claude (claude.ai, Desktop, mobile and Claude Code). This is an inbound integration: the assistants call Leitagu.
  • Used for. Staff working in the CRM and setting up stores through an assistant, as themselves.
  • App. Admin.
  • Settings. ADMIN_URL must be exactly the public address, because it is the OAuth issuer.
  • Endpoints. /api/mcp, /.well-known/oauth-*, /oauth/authorize, /api/oauth/{register,token,revoke,authorize}. The admin app fetches a client's metadata document (for Claude, from claude.ai) with a 5-second limit; codes are only sent to the person's own computer or to claude.ai.
  • Code. packages/core/src/server/oauth.ts, mcp.ts, mcpTools.ts. Details in AI assistants (MCP).

Estonian business register

  • What. e-Äriregister (ariregister.rik.ee).
  • Used for. Only a link: a CRM company with a registry code links to its register entry. Nothing is fetched from it.
  • Code. apps/crm/src/app/(crm)/companies/[id]/page.tsx.

What Leitagu does not use

  • Analytics. Page views are counted by Leitagu itself: the shop and the hub send them to the shop's /api/collect, with no cookies and no outside service. See Traffic analytics.
  • Login providers. Accounts are Leitagu's own email and password; staff sign in to the CRM and partner app through the admin app.
  • Payments, maps, SMS and file storage. None in the code. Product images are links to the stores' own image addresses, and room photos are sent to Claude, not stored.
  • Fonts and 3D. Geist and three.js are npm packages bundled with the apps, not loaded from another site.

Infrastructure

Coolify on DigitalOcean

  • What. Coolify, a self-hosted platform for Docker apps, on a DigitalOcean droplet. Its interface and API are at servers.leitagu.ee.
  • Used for. Running the apps from their images and the PostgreSQL 16 database (resource leitagu-postgres), with the apps' environment variables and domains, and running the database backups.
  • Endpoints. The images workflow calls https://servers.leitagu.ee/api/v1/deploy?uuid=<app>&force=true for each app and polls /api/v1/deployments/<id> until it finishes. The app uuids are in the workflow (they are not secret).
  • Settings. COOLIFY_DEPLOY_TOKEN, a GitHub repository secret: a Coolify API token with the deploy and read abilities. Coolify itself needs registry credentials with read:packages to pull the private images (Keys & Tokens → registry credentials).
  • When it fails. The deploy job marks an app failed if the request fails or the deployment doesn't finish within 10 minutes, carries on with the next app, and fails the run at the end. The apps that weren't deployed keep running their previous image.
  • Scheduled tasks and backups. Coolify also runs the store sync and the CRM mailbox read as Scheduled Tasks, and the database backups; see Scheduled jobs and Backups and restore.

GitHub Actions and ghcr.io

  • What. GitHub Actions builds the images; GitHub Container Registry stores them as ghcr.io/leitagu/leitagu-<app> (private).
  • Used for. On a push to main: build the apps the change touches, start each image against a throwaway Postgres and check it, push it with the tags latest and sha-<short commit>, then deploy through Coolify in the order web, admin, crm, partner, docs. Pull requests build and check their images and push them as pr-<number>. Actions → images → Run workflow builds chosen apps by hand.
  • Code. .github/workflows/images.yml, Dockerfile. Pushing uses the built-in GITHUB_TOKEN.
  • Details. DEPLOYMENT.md, "Option C: container images".

Cloudflare R2

  • What. Cloudflare R2 object storage, bucket leitagu-backups, in the EU jurisdiction.
  • Used for. Off-site copies of the database dumps and of Coolify's own backup, kept for 90 days. Coolify uploads them; the apps don't use R2.
  • Settings. The R2 endpoint and access keys are set in Coolify and kept in the password manager, not in the repository.
  • Details. Backups and restore.

zone.ee (domain and DNS)

  • What. zone.ee, the Estonian registrar where leitagu.ee is registered. Its DNS is managed there too, as for the team's other domains.
  • Names. leitagu.ee, www, admin, partner, crm and docs point at the hosting (DEPLOYMENT.md, "What you need"), and servers at Coolify.
  • Who changes it. Mihkel, in the zone.ee control panel. A new subdomain or a move to another server starts there.
  • Not Cloudflare. Cloudflare is used only for R2 backups; DEPLOYMENT.md mentions Cloudflare Access only as an option in front of the staff apps.