v0.1.0 Latest

Domain checks

DNS, TLS, RDAP, mail posture, and website branding per domain record, on request and on a schedule in three layers, with webhooks for what changed and what is expiring.

A doc type with a field marked as holding a domain (fields.domain_role = domain) gives its documents a Domain checks panel. The starter Domain/DNS type has one; point the role at a field on a doc type of your own and it works there too.

The checks

CheckDefault cadenceWhat it keeps
DNS recordsdailyA, AAAA, MX, NS, CNAME, TXT. TXT records are listed one per line with what each is for named: SPF, DMARC, DKIM, and verification tokens (Google, Microsoft 365, Atlassian and others). Who is answering is compared with the DNS Host field.
TLS certificatedailyIssuer, what it covers, whether the chain is trusted, days remaining.
Domain registration (RDAP)weeklyRegistrar, created, expires, transfer lock. Offered to the Registrar and Expiration fields with Use this.
Email postureweeklySPF, DMARC (and its policy; a DMARC hosted elsewhere by CNAME is followed), DKIM at the common selectors or the ones the record names. Shown as a table of check, finding, and record.
Website brandingon requestThe site’s title, theme color, icons and manifest, read from its front page. Offered on the company’s edit page; Use as company theme makes the icon the logo and the color the accent.

Running them

Check now runs the ticked checks immediately. Running one needs the document-editing permission, because it is outbound traffic on the instance’s behalf, and the whole instance shares a budget of 30 runs a minute.

With Check automatically on (the default), the worker re-runs each kind on its own clock. How often is a policy in three layers:

  1. Instance. Admin → Settings: the intervals everything follows, and the certificate notice (30 days). Zero turns a kind off everywhere.
  2. Company. On the company’s edit page, different intervals for that company’s records; null follows the instance, zero turns a kind off there.
  3. Record. On the record, its own intervals, or opt out of the worker altogether. A record can also say its certificate renews on its own, in which case its expiry is not announced unless the record sets a notice anyway.

A new record states nothing and follows its company and, through it, the instance. Each kind keeps its own next time; a run replaces only the sections it fetched, so every section shows its own age. The worker takes what is due oldest first, within the same budget a person’s clicks share, and puts off a record whose domain is empty or malformed until next time with the reason shown on the record. /api/internal/webhooks runs the same pass for deployments with no timer.

What is announced

Each run is boiled down to a summary (name servers, addresses, mail exchangers, certificate and its expiry, registrar, registration expiry, transfer lock, SPF, DMARC policy, DKIM) and compared with the last. Only facts known on both sides are compared, so a check turned on or a lookup that failed once is not a change.

  • domain.changed: { id, title, company_id, domain, checked_at, changes: [{ what, from, to, message }] }. what is one of resolves, ns, a, mx, certificate, certificate_trust, registrar, registration_expiry, transfer_lock, spf, dmarc, dkim.
  • domain.expiring: { id, title, company_id, domain, checked_at, kind: "certificate" | "registration", expires_on, days_remaining }. Once per expiry date. A certificate is announced inside the notice its record, company or instance sets, and never when the record says it renews itself without asking for a notice. Registration keeps a fixed 60-day notice.

Admin → Notifications lists what the last check of every domain record flagged, across the companies you can see: the same facts the webhooks carry.

Safety

  • The domain is user input, so a lookup is treated as untrusted: names are resolved first, anything that is not a public address is dropped, and the TLS connection is made to the vetted address with the name presented for SNI, which also closes DNS rebinding. Website icons are fetched the same way, sniffed (PNG, JPEG, WebP, or an SVG rendered to PNG), capped at 1 MB, and served through the record’s own route, never hotlinked.
  • A finding never edits the record on its own. Accepting one is an ordinary save with a revision and an audit entry; a registrar name not yet in the shared dropdown is added to it, and an existing option wins even when the wording differs.
  • DNS and TLS need Node, so on Workers those sections report that they are unavailable. RDAP is plain HTTPS and works anywhere. Website branding’s SVG rendering needs native code and is skipped on Workers.