820 Commits

Author SHA1 Message Date
mintlify[bot] a1ddd52fb6 docs: improve SEO titles and descriptions on introduction pages 2026-08-17 02:30:25 +00:00
Tony Chang 6f7fcf7a90 docs: agents-only pointer to agents.insforge.dev on introduction page (#1971)
* docs: add agents-only pointer to agents.insforge.dev on introduction page

Adds a Mintlify <Visibility for="agents"> block below the existing hidden
agent instruction, pointing agents to the Sherpa-run agent-workflow site.
Renders only in the .md/agent view, invisible on the human web page.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YZaoLMs3PseiLeivXfZWwH

* docs: mirror agents-only pointer in es/zh/zh-Hant introductions

Per DOCS_I18N, locale trees mirror English structure; agent-facing text
stays English, matching the existing hidden agent div in these files.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YZaoLMs3PseiLeivXfZWwH

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-16 19:28:29 -07:00
mintlify[bot] ee7268d6ad docs: expand compute overview description for SEO 2026-08-12 03:36:51 +00:00
Lyu d594a36daa fix(compute): address the #1930 review — startup race, wrong-provider create, form hygiene
**The startup race both bots flagged is real, and its effect is permanent.** The
listener opens before stored credentials and settings are read, and the provider
registry is a field initialiser — so a compute request landing inside those two
reads constructs the registry from environment-only values and that choice sticks
for the life of the process. A provider configured only through the dashboard would
stay missing until the next config write. The registry is now discarded after
priming, so an early build cannot outlive it.

**A create from a non-default provider's page went to the wrong driver.** The
dialog never received a provider: it read the default provider's capabilities and
the request carried no selection, so on `/dashboard/compute/fly` with Docker as
default the service was created on Docker and then filtered out of the page that
created it. `createServiceSchema` takes an optional `provider`, the service layer
resolves the driver from it, and a named provider that is not configured is
rejected rather than silently swapped — a row that disagrees with where the
container runs is the failure the capability layer exists to prevent. Omitting the
field still uses the default, so the CLI is unaffected.

Also from the review:

- `updateConfig` re-primes in a `finally`. A failure part-way through left earlier
  writes persisted while the in-memory snapshot still described the pre-write state.
- The landing redirect validates `configured[0]` against the slugs the dashboard has
  pages for. An unrecognised one redirected here, got bounced back by the page's own
  slug guard, and looped.
- `DockerSettingsForm` seeds once. A refetch while someone was typing replaced their
  input with what the server still had.
- Both settings forms catch `mutateAsync` rejections — `void handleSave()` left them
  unhandled. The Fly form also keeps its fields on failure: it holds a pasted token,
  and clearing it made the retry a re-paste.
- The save toast said "Fly credentials saved" after saving Docker settings; both
  forms share the mutation. Now provider-neutral, in four locales.
- `ComputeLayout.test.tsx`: `beforeEach` did not reset `meta.value`, so the spinner
  test depended on execution order, and `enabledCalls.every(...)` passed on an empty
  array, so the fail-fast gate was unverified if the hook never ran.
- The dev compose comment described the production image's entrypoint. That service
  builds `target: dev`, which runs as root and needs no group handling.
- Spanish docs: singular verb after the line count changed to one.

Declined, with reasons in the PR thread: the ast-grep SQL-injection flag (column
names come from a fixed map, values are parameterised), the prettier violation
(prettier and eslint are both clean on that file), and a cross-field Zod refine on
`computeCapabilitiesSchema` (nothing parses it at runtime, so it would be dead code
that could only hard-fail metadata if it ever ran).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-11 17:44:48 -07:00
Lyu 526e0f280a feat(compute): read the Docker socket's group instead of asking for it
Enabling Docker took three steps because the production image runs as `node` and
the socket is mode 660 root:docker, so a matching group was required. The group id
is host-specific — 0 on Docker Desktop, commonly 999 on Debian/Ubuntu, 993 on
Amazon Linux 2023 — and a wrong value is a silent EACCES that shows up as "Docker
never appears in the dashboard". There is no value that is right everywhere, so
there is no default to ship.

The container can read it off the socket. The runner stage no longer sets
`USER node`; a new entrypoint starts as root, takes the socket's group with
`stat -c %g`, joins it, and execs the command through `su-exec node`. The app
process is still `node` and `tini` is still PID 1. With no socket mounted it
drops to `node` and does nothing else, and a deployment that pins `user:` is
left alone.

`group_add` and `DOCKER_GID` are gone from all five compose files, `.env.example`,
the docs in four languages, the dashboard guide (three steps to two) and the
not-configured API message. Uncommenting one volume line is now the whole edit.

The mount stays opt-in: the socket is root-equivalent on the host, and on by
default would hand every deployment's backend the ability to take over its host
whether or not it uses compute.

Verified on a build of `target: runner` — no socket: uid 1000; socket at gid 0:
joins root, writable; socket at gid 999 with the group already present: joins it,
writable; and the old `USER node` path with no entrypoint: denied, which is the
failure the removed step existed to avoid. Then end to end from that image
against a live database: provider ready, metadata slice present, a service
created and serving on its published port.

Also batches the compute logs limiter test. 120 sequential requests overran the
10s timeout on a busy machine and 120 simultaneous ones had connections dropped;
ten in flight is neither, and the assertion is by count rather than position.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-11 16:48:56 -07:00
Lyu 7701a1da82 fix(compute): correct the Fly setup instructions
Both commands are real — `fly tokens create org` is "Create org deploy tokens"
and `fly orgs list` is "Lists organizations for current user", checked against
flyctl v0.4.60 — but the copy around them was wrong. Rendering the page in a
browser rather than reading the source showed why: the locale files still held an
older design's strings, and a locale value beats a component's defaultValue.

- Step titles carried a leading "1."/"2."/"3." while StepItem renders the
  circled number, so every step showed its number twice.
- Fly's step 2 read "Set both values in .env" — the screen it labels has the
  form in it, and .env is exactly what it exists to avoid.
- The commands ran in the wrong order with no `-o`. `tokens create org` takes the
  slug, and without it flyctl stops to ask for an org you have not looked up yet.
  .env.example already had the flag; the panel had dropped it.
- The field hints repeated the command with literal backticks. They now say what
  the value is — an org slug is not a display name, which is a real mistake to
  make.

Also strips a leading `FlyV1 ` when a token is stored. The CLI prints the
macaroon with its scheme attached, and copying that line as printed is the
obvious thing to do — but the logs endpoint prepends `FlyV1 ` itself (it rejects
`Bearer`, verified live in the container-logs work), so a verbatim paste would
send the scheme twice and break the logs panel while machines kept working. A
token without the prefix is untouched.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-11 16:48:56 -07:00
Lyu e9a5a47fcc fix(docs+dashboard): review round on the Docker compute surface
Fixes the failing vale-spellcheck and the valid review comments.

Vale rejected Traefik and SELinux, both legitimate proper nouns; added to the
Mintlify accept list, which already carries Coolify, Dokploy, flyctl and nginx.

Docs, all four locales:

- The ingress default was stated as universal (`none`), contradicting the capability
  table further down the same page which shows Fly offering only a hostname. It now
  says the modes and the default both depend on the provider, and that a mode the
  provider cannot give is coerced rather than rejected.
- The build example used `$ID` without ever assigning it, so copy-pasting it posted
  to `/api/compute/services//build`. Step 1 now captures the id from the response.

Dashboard:

- ServiceCard looked capabilities up by the deployment's *default* provider while
  each service row carries its own. Providers coexist and the backend routes per
  row, so a Docker service in a Fly-default deployment showed the meaningless region
  `local`, and a Fly service in a Docker-default deployment hid the region it
  genuinely has. The hook now takes an optional provider name; the card passes the
  service's own, the create form keeps using the default.
- The ingress chip rendered the raw enum (`port`) because the i18n keys did not
  exist. `compute.fields.ingress` and `compute.ingressModes.*` are now defined in
  all four locale files, alongside the region keys that were already there, and the
  chip falls back to the same friendly label table the create dialog uses.
- Corrected the comment on the capability fallback. Region falls back to shown and
  ingress to hidden, which looks inconsistent but is deliberate in both directions:
  a pre-capability backend is a Fly backend where regions are real, and it has no
  ingress field at all, so an ingress control there would silently do nothing.

Tests: the ingress case now opens the select, asserts the options are filtered to
what the provider reported, picks one and checks it reaches the payload — it
previously only checked the field's presence and the default. Four new ServiceCard
tests cover the per-provider lookup, the friendly label, region retention for a
region-capable provider, and the unknown-provider fallback. Radix's Select needs
pointer-capture and scroll shims under jsdom; no other test in this package opens
one. Both fixes verified by reverting them and watching the tests fail.

Not changed: CodeRabbit asked for the hook filename in kebab-case per a repo
guideline, but all 64 hooks in this package are camelCase and none are kebab-case,
so the new file matches its siblings.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-11 16:48:56 -07:00
Lyu ed31cc185e docs+dashboard: cover the Docker compute provider
Follows the self-hosted Docker driver (#1892), which shipped without any of the
user-facing surface.

Docs, all four locales. The compute overview still said containers run on Fly.io and
told self-hosters to bring a Fly account. It now documents both providers behind
tabs, the socket-mount opt-in with the host-specific DOCKER_GID (and the Docker
Desktop difference, where the socket is root:root so the value is 0), the three
ingress modes with the loopback bind default, source builds through
POST /:id/build, the platform support tiers, and a capability table so a reader can
see what Docker cannot do. Two claims on that page were false and are now true:
nothing is injected into a container's environment — verified across the OSS
service layer, the Fly provider and the cloud backend, all of which send only the
caller's env vars — and there is no replica count, so the page no longer offers to
scale horizontally.

Dashboard. The create dialog offered a region picker to every provider, so a
self-hoster on Docker picked a region that went nowhere. It now reads the compute
slice of /api/metadata: region is hidden and omitted from the payload when the
provider has none, and an ingress control appears when more than one mode exists —
without which every dashboard-created service on Docker would be private and
unreachable, since `none` is the default. Undefined capabilities means "not known
yet" (loading, compute off, or a backend older than the slice) and shows everything,
which is the previous behaviour and stays correct against an older backend. The card
shows ingress instead of the region chip where region is meaningless.

Adds CreateServiceRequestInput (z.input) so a caller can legitimately omit a field
that has a schema default, following the ...BodyInput precedent in the payments
schema. Four dashboard tests cover the gating in both directions; verified by
reverting the gate and watching the Docker cases fail.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-11 16:48:56 -07:00
jfeng 6124c3081a Merge pull request #1913 from Harsh-Daga/feat/deploy-backup-script
feat(deploy): add deploy/backup.sh for self-host backups
2026-08-11 07:49:29 +08:00
insforge-docs-bot[bot] 67f9d162ea docs: document deleting a project via CLI and dashboard (fixes askai 01KY4DVKNFF3F1DN9CGAM6BBTM) (#1914)
Co-authored-by: insforge-docs-bot[bot] <insforge-docs-bot[bot]@users.noreply.github.com>
2026-08-10 13:01:01 -07:00
Harsh Daga 74e13faddf feat(deploy): add deploy/backup.sh for self-host backups
Ship a maintained backup script that pg_dump's Postgres and copies .env,
include it in the setup.sh sparse checkout manifest, and point the
deployment security guide at the script instead of an inline copy-paste.
2026-08-09 07:04:52 +00:00
Harsh Daga c3adb5af6b docs(deploy): add Hetzner Cloud VPS self-host guide
Add a step-by-step deployment guide for Hetzner Cloud that follows
the existing AWS EC2 walkthrough pattern: server and firewall setup,
deploy/setup.sh bootstrap, verification, and optional TLS via Nginx.

Update the deployment README and docs nav. Firewall guidance matches
the self-host compose file (internal services on 127.0.0.1 only).

Closes #1909
2026-08-09 05:12:31 +00:00
mintlify[bot] 244c666781 docs: expand zh/zh-Hant deployment security guide descriptions for SEO 2026-08-07 23:31:16 +00:00
Lyu 6f865dbbd2 docs(deploy): lead with the steps
The rollback section and setup.sh's header had grown more explanation than
instruction. Section 16.2 is four numbered steps now, with one sentence on the
consequence of skipping the last one; the three paragraphs justifying the
approach are gone. setup.sh's header keeps the usage lines and the environment
variables and drops the reasoning behind them, and the same trim runs through the
comments inside — 259 lines to 243.

INSFORGE_REF now says what it accepts: a tag, branch or commit. It takes all
three (raw.githubusercontent.com resolves each, and git clone --branch covers the
first two), and the previous wording implied releases only.

Also removes a stray blank line and shortens the two access-key comments in
.env.example, left over from the variables that came out of this branch.

Re-ran the setup.sh matrix after the trim, since comment edits in a shell script
are not as safe as they look: both acquisition modes, ref pinning in each, all
three guards, and the fail-closed path — 10 checks, no failures. The structural
checks pass too.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 16:27:19 -07:00
Lyu 2f285b38ad docs(deploy): say to remove the pin, and not to overwrite COMPOSE_FILE
Two gaps cubic found in the rollback procedure.

It said to append pin.yml to COMPOSE_FILE and never said to take it out. Section
15's update then pulls new images and keeps running the pinned one — the pin wins
over latest, silently, for as long as the entry is there. So a rollback that was
meant to be temporary becomes permanent, and looks like updates that stopped
working.

And the example showed a whole COMPOSE_FILE line, while the instruction said to
append. Anyone with a storage overlay already in that variable would copy the
example and drop MinIO or RustFS out of their stack. The example keeps the old
value in a comment above it now, so what is being appended to is visible.

Four locales.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 16:18:05 -07:00
Lyu c6181a312c fix(deploy): drop the two variables an overlay already covers
INSFORGE_OSS_VERSION and INSFORGE_DEPLOYMENT_METHOD do not earn their place. A
caller can already override an image and add environment variables the compose
file never mentions, by appending an overlay to COMPOSE_FILE — the mechanism the
storage overlays use, documented in .env.example, needing nothing from here:

  services:
    insforge:
      image: ghcr.io/insforge/insforge-oss:v2.2.9

That is strictly better than the variable it replaces: it pins any image in the
stack, not only this one.

I also overstated the case for the version variable. I said a rollback that
edited the compose file would leave the install unable to update, because
`git merge --ff-only` refuses when a tracked file has local changes. It refuses
only when upstream also changed that line; otherwise the merge succeeds and
keeps the edit. The overlay avoids the question entirely by being a file of the
operator's own, and section 16 now teaches that instead.

Dropping the telemetry stamp also avoids a behaviour change nobody asked for:
with a `docker-compose` default, every existing self-host would have started
reporting `docker-compose` where it reports `docker` today.

ACCESS_API_KEY and ACCESS_ANON_KEY stay, for a reason that has nothing to do
with any caller: .env.example documents both as settable, and this compose file
silently dropped them, so a self-hoster who set them saw no effect. That is the
same inconsistency as section 5.4 telling people to set AWS_* variables the file
does not pass.

Verified on a running stack: the overlay pins insforge-oss to v2.2.9, adds
INSFORGE_DEPLOYMENT_METHOD which the base file never names, and the injected
ACCESS_API_KEY answers 200 on /api/database/tables.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 15:39:31 -07:00
Lyu decdc23756 docs(deploy): make the rollback procedure something you can follow twice
Section 16 told the reader to edit docker-compose.yml to pin an older image.
That fights section 15: updating runs `git merge --ff-only`, which refuses when
a tracked file has local changes. So following the rollback once left the
install unable to update until the edit was reverted — and nothing said so.

It sets INSFORGE_OSS_VERSION in .env now, which is the file that belongs to the
operator and that no update touches. That is what the variable is for, and this
is the procedure that needed it.

Two things in that section were also no longer true:

- It said `deploy/docker-compose` pins v1.5.0 and the project is on 2.x. That
  file pins insforge-oss to latest, and the other three images to their own
  upstream versions.
- It opened by restoring `docker-compose.yml.old`, a file no step in this guide
  ever creates. Section 14 backs up .env and records image versions, which is
  what the rewritten procedure uses.

16.2 and 16.3 collapse into one step, so the rest of the section renumbers.
Four locales.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 15:33:50 -07:00
mintlify[bot] 7a85010ed4 docs: trim overlong descriptions on Coolify and Dokploy deploy pages 2026-08-07 19:22:22 +00:00
Lyu efa6696ae1 fix(deploy): audit the corpus against invariants instead of grepping for reports
The steady trickle of small findings has one cause: I have been fixing this
corpus with grep-driven sweeps, and every pattern has been narrower than the
corpus. 30 of these files are near-duplicate translated prose, so each logical
fix landed in twelve files and missed four — the variants being case
(`~/InsForge` vs `~/insforge`), indentation (fences nested in list items),
translated phrasings that do not match the English anchor, and code comments
rather than prose. Reviewers then found the remainder, one batch at a time.

So this pass wrote the invariants down and checked all 34 changed deploy files
against them mechanically. Thirteen rules, ten violations, all fixed:

- Azure's update commands used `~/InsForge` while its setup step creates
  `~/insforge` — case-sensitive on Linux, so the documented update fails before
  it starts. Four locales.
- The image-only compose probed `pg_isready -U postgres` with POSTGRES_USER
  configurable one line above, so overriding the user left Postgres permanently
  unhealthy and, since insforge gates on it, never started the backend. The same
  class of bug as the postgrest healthcheck, in the same file. Verified: with
  POSTGRES_USER=ifadmin the container now reaches healthy.
- The update procedure's review diff covered `deploy` and `.env.example` but not
  `functions/`, which is in the sparse checkout and which the Deno service
  executes. Four locales.
- Section 5.2 still told the reader to set POSTGRES_PASSWORD, two sections after
  4.2 started the stack — and Postgres only reads it at cluster init, so the
  instruction could not work. It says so now. Four locales.
- setup.sh only added COMPOSE_FILE when absent, so a .env copied from the
  template by hand kept pointing at the development stack, whose files the
  checkout does not contain. It now repoints that exact value, and leaves
  anything else — including a hand-appended storage overlay — alone.
- MD040 on two fences, and the update prose that called an update "a pull and
  restart" when the checkout carries Postgres's config and the Deno functions.

The audit also caught something no reviewer did: .env.example's COMPOSE_FILE has
to stay equal to what Compose discovers on its own in that directory, which
changed when docker-compose.override.yml was deleted earlier in this branch.
It is equal — verified byte-for-byte against auto-discovery — and setup.sh's
self-heal constant now has to match it, with both sides commented.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 11:53:09 -07:00
Lyu 1605314b3e fix(deploy): close the gaps the second review round found
From cubic's pass, after reproducing each:

- setup.sh's migration branch exits before the fresh-install path's `chmod 600`,
  so an install whose old .env was group-readable stayed that way. It now
  chmods right after the move; verified by handing it a 644 file.
- The multi-instance section had `cp .env.example .env.projectN` with no further
  instruction, and .env.example now ships COMPOSE_FILE's development value —
  a file the sparse checkout does not contain. Each copy needs the production
  path.
- ROOT_ADMIN_PASSWORD is mandatory in the platform files now, alongside
  JWT_SECRET and ENCRYPTION_KEY. Unlike POSTGRES_PASSWORD there is no migration
  hazard: auth.service.ts hashes it from the environment on every boot rather
  than persisting a record, so changing it takes effect on restart. A dashboard
  reachable from the internet on `changeme123` is the most directly exploitable
  of the three placeholders.
- The zh, zh-Hant and es guides' section 5.5 still listed AWS_S3_BUCKET/AWS_*,
  which the compose file does not pass, while English had moved to S3_*. The
  note I added to 5.4 pointed at "the S3_* variables in 5.5" — which did not
  exist in those three. Aligned on the names the compose actually reads.
- GCE's backup snippet still said "run from deploy/docker-compose/" in a code
  comment, which the earlier path sweep did not match.
- Containarium's agent flow wrote the whole of ~/insforge/.env, overwriting the
  secrets setup.sh had just generated two steps earlier.

Also updates the backend skill note, which claimed the two platform files differ
only in INSFORGE_DEPLOYMENT_METHOD; the build context differs too, since Coolify
builds with --project-directory and Dokploy does not.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 11:41:09 -07:00
Lyu 9558b7b750 fix(deploy): pass Vercel credentials through, and re-apply the sparse checkout
Review on #1887 caught two real gaps.

The platform files dropped VERCEL_TOKEN, VERCEL_TEAM_ID and VERCEL_PROJECT_ID
— the only three variables the image-only compose passes that they did not —
so site deployments and custom domains ran without credentials. Both guides
tell the reader that .env.example lists every supported variable, which made
that silent.

None of the cloud guides re-ran setup.sh after `git pull` in their update
sequence. A release that adds a file the compose reads also adds its path to
the script, and without re-applying, the merge lands the file in git but never
in a sparse working tree — the stack then starts against a file that is not
there. Only the security guide had this step.

While checking those: sixteen prose references still pointed readers at
`~/insforge/deploy/docker-compose` as the directory to run commands from. Four
were the Azure guide's `~/InsForge/...`, which the earlier case-sensitive sweep
missed.

Also settles the Coolify verification gap this PR shipped with. Coolify binds
domains per compose service through `docker_compose_domains` on the
application, which was null, which is why its auto-assigned FQDN returned 404.
Set to bind insforge, a real deploy answers /api/health over the domain, and an
edge function created and invoked through it returns the worker's body — as
does hitting http://deno:7133 directly, so service-name resolution works under
Coolify's networking. Verified with real secrets: PATCH, not POST, is what
updates an environment variable Coolify already discovered from the compose
file.

Vale flagged three words in the new guides. Coolify joins Dokploy and Zeabur in
the vocabulary; "undecryptable" and "preloads" are rewritten rather than added.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 11:16:37 -07:00
Lyu 5b0accd906 docs(deploy): document the verified flow in all four locales
- The quickstart is the setup.sh one-liner, with a download-and-read variant
  for anyone who will not pipe a script to a shell. The old "do the same by
  hand" block reproduced the script's sparse-checkout list, which had already
  drifted once when the list gained deploy/setup.sh and the copy did not.
- Every command runs from the checkout root. The four cloud guides (AWS EC2,
  Azure VM, GCE, Containarium) cloned the full monorepo — 1,782 files, 57.6MB —
  and then ran the image-only compose file anyway; none reference a build step.
  They use setup.sh now, which also stops walking the reader through inventing
  JWT_SECRET by hand or pasting a placeholder over a generated secret.
- New Coolify and Dokploy guides. Both platforms had compose files in the repo
  and no documentation; Coolify appeared once, in a list of telemetry values.
- COMPOSE_PROJECT_NAME is documented with its consequence: any .env on the host
  carrying the same name means `docker compose up` there adopts and recreates
  that project's containers.
- self-host-storage.mdx covers the image-only stack, which it never did —
  appending an overlay to COMPOSE_FILE rather than passing -f flags.
- Section 5.4 no longer tells self-hosters to set AWS_ACCESS_KEY_ID and
  AWS_SECRET_ACCESS_KEY; the compose file passes neither.
- The automated backup script pointed -f at a compose file the checkout does
  not contain, and -f alone loads neither COMPOSE_FILE nor
  COMPOSE_PROJECT_NAME from .env, so its `exec` would not have found the
  container.

Registered in docs/deployment/README.md and docs.json's English tree, locale
trees regenerated with scripts/build-docs-langs.py. The i18n parity check
reports the same 24 pre-existing gaps as before.

Not verified: the domain-assignment step in the two platform guides. Coolify's
auto-assigned application FQDN returns 404 because a compose deployment binds
domains per service, and I found no API field for that; the Dokploy stack was
checked over the container network. Both steps follow the platforms' own docs.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 10:54:19 -07:00
jfeng d860064c87 Merge pull request #1859 from Gautam-aman/docs/openapi-usage-spec
docs(openapi): add usage API specification
2026-08-05 17:31:11 -07:00
yaowenc2 cb7df81335 docs: disable PostHog session recording on docs
Keep pageview/event analytics; session replays add client-side rrweb
overhead without much value on a public docs site.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NcFYkLqoAuXW2fPbNm11V9
2026-08-04 12:52:54 -07:00
yaowenc2 a71c779bce docs: make PostHog sessionRecording explicit
Review suggestion from John-bot and CodeRabbit: state the default
instead of relying on it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NcFYkLqoAuXW2fPbNm11V9
2026-08-04 12:47:15 -07:00
yaowenc2 4b6754b6f3 docs: send docs analytics to PostHog
Adds the Mintlify PostHog integration to docs.json using the same
public project key (phc_) the dashboard already reports to. Events
route through Mintlify's default proxy (ph.mintlify.com); session
recordings additionally require the docs domain to be added to
PostHog's authorized domains for recordings.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NcFYkLqoAuXW2fPbNm11V9
2026-08-04 12:38:21 -07:00
Aman Gautam e06e149049 docs(openapi): add usage API specification 2026-08-04 18:03:34 +05:30
mintlify[bot] 4a6a14f486 docs: improve SEO titles and descriptions across all languages 2026-08-03 22:40:22 +00:00
ayaangazali 944b235c4a docs: publish the deployments and dashboard API references
openapi/deployments.yaml and openapi/dashboard.yaml are maintained in the repo
but never referenced from docs/docs.json, so neither reaches the docs site. The
other fourteen specs each appear once per language. That leaves 15 documented
endpoints, 14 deployments paths and 1 dashboard path, with no published
reference: https://docs.insforge.dev/api-reference/deployments returns 404.

Register both specs in all four language navigations, matching the existing
entry shape. Group names are left in English because these navigations already
keep Tables, Records and Schedules in English; happy to localise them if you
would rather.
2026-08-02 18:17:46 -07:00
insforge-docs-bot[bot] ccc83c6fd7 docs: import Postgres atomically and note imported tables need access setup 2026-08-01 17:01:57 -07:00
insforge-docs-bot[bot] 3542987a4b docs: import existing Postgres database into InsForge (fixes askai 01KYPE8JDMYBTDG04YTFBGZB4V) 2026-08-01 16:26:18 -07:00
Lyu 169dc3ab68 Merge pull request #1829 from InsForge/claude/oss-telemetry-enhancements-d3584e
feat(telemetry): report which features a self-hosted instance uses
2026-07-31 18:00:26 -07:00
Lyu c18345ddbf fix(telemetry): count policy denials as feature usage
Excluding 403 alongside 401 was wrong. A 403 usually means the request
did reach the feature and was denied by policy: RLS denials surface as
403 (SQLSTATE 42501 maps to it in errors.ts), storage permission checks
raise it in six places, and disabled signups return it from auth. Those
requests exercised the feature, so dropping them undercounted exactly
the projects that configure RLS properly.

Only 401 is excluded now, which still covers both cases the exclusion
was added for: an unauthenticated probe, and the rejected read a
dashboard tab fires when its 15-minute token expires.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-31 17:45:45 -07:00
Lyu e9adf313e5 feat(telemetry): report which features a self-hosted instance uses
Telemetry previously reported only whether optional services were
configured, which says an admin pasted an API key, not that anyone uses
the feature. Heartbeats now carry the set of features touched since the
previous heartbeat.

It is a yes or no per feature, not a count: no request volumes, paths,
payloads, or anything about who made the request. Reads from a dashboard
session are ignored, since a tab left open would otherwise mark half the
product as used, and dashboard sign-in traffic under /api/auth/admin is
excluded for the same reason. Dashboard writes still count.

The S3 protocol gateway and direct edge-function invocations are counted
toward storage and functions: both bypass the /api router, and both are
the surfaces a finished app actually calls.

Shutdown now sends a final heartbeat, so instances that run for less
than the heartbeat interval still report.

Unchanged on InsForge Cloud, which is gated twice: the middleware is
never registered, and the service never starts.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-31 17:00:10 -07:00
mintlify[bot] 35963cb5fe docs: improve SEO titles and descriptions for webscraper overview translations 2026-07-31 05:15:09 +00:00
Carmen Dou af509b7e8e Merge pull request #1824 from InsForge/feat/webscraper-self-hosting-pr
feat(webscraper): self-hosting support via a developer-supplied Apify API token
2026-07-30 22:14:15 -07:00
CarmenDou aec1c2cf58 fix: address review findings on self-hosted web scraper 2026-07-30 17:53:21 -07:00
Carmen Dou 685efe3d47 Merge pull request #1732 from Gautam-aman/docs/schedules-openapi
Add OpenAPI specification for schedules API
2026-07-30 17:40:34 -07:00
Wayne Hsu 4c10f5c498 fix(auth): address native Apple review feedback 2026-07-30 18:16:25 +01:00
Wayne Hsu 0e4c0877e6 feat(auth): add native Apple ID token sign-in 2026-07-30 15:48:54 +01:00
Lyu 01c46a8dae Merge pull request #1820 from InsForge/feat/self-hosted-scheduled-backups
feat: scheduled database backups for self-hosting
2026-07-29 14:47:32 -07:00
Lyu 287fcff194 feat: scheduled database backups for self-hosting
Self-hosted deployments previously supported manual backups only. This
adds an in-process backup scheduler with retention, configured through a
new Database Settings dialog in the dashboard.

Backend:
- system.database_config singleton (migration 061) holding backup_enabled,
  backup_cron_schedule, and backup_retention_days, following the
  realtime/schedules config conventions; future database-level settings
  share this table.
- Node-side scheduler in DatabaseBackupService: a one-minute tick computes
  due-ness from persisted state (most recent UTC cron fire vs last
  scheduled attempt and last config change), so missed fires run shortly
  after a restart and enabling a schedule never fires retroactively.
  pg_cron is not used because backups need the backend to spawn pg_dump
  and stream artifacts through the storage provider.
- Cron expressions are free-form 5-field, validated to fire at most once
  per hour (single literal minute field).
- Retention prunes expired scheduled backups (artifact included) right
  after each successful scheduled run, while the in-flight guard still
  blocks restores. Manual backups are never auto-deleted.
- GET/PATCH /api/database/backups/config (admin, audited); the whole
  backups router remains unmounted in cloud environments, and the
  scheduler only starts outside them.

Dashboard:
- Database Settings dialog (gear on the Database sidebar, Configure on
  Backup & Restore): enable toggle, preset chips + cron input with
  client-side validation and a next-backup readout, retention select.
  Schedule controls gray out while disabled. Cloud mode never shows it.
- Backups page renders the Scheduled Backups section in self-hosting with
  status, restore, and delete per row.
- New i18n keys in en/es/zh-CN/zh-TW.

Tests:
- Unit: schedule helpers (due-ness, validation), scheduler/prune/config
  service paths, migration guards, settings dialog component tests.
- Integration (real Postgres + pg_dump/pg_restore in CI): config
  defaults/validation, full backup -> restore -> delete round-trip, and
  scheduled-run retention pruning.

Also verified live against a running stack on both local-disk and MinIO
(S3) storage, including restore-from-artifact and prune.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-29 12:33:41 -07:00
mintlify[bot] ff9733de42 docs: expand SEO descriptions for pricing and functions overview pages 2026-07-27 22:32:45 +00:00
mintlify[bot] 49172d134a Merge remote-tracking branch 'origin/main' into mintlify/b728566c 2026-07-27 22:29:49 +00:00
Carmen Dou d2dc365256 Merge pull request #1808 from InsForge/2026-07-27-carmen-fix-mintlify-docs
2026-07-27 fix mintlify docs (Carmen)
2026-07-27 15:29:35 -07:00
mintlify[bot] 9476f041da docs: improve SEO descriptions for auth REST API pages 2026-07-27 22:27:36 +00:00
Lyu 91d60fc85c Merge pull request #1798 from InsForge/codex/ins-521-email-otp-auth
feat(auth): add email OTP sign-in
2026-07-27 15:25:28 -07:00
Carmen Dou 1fc0a2ec1a docs: align usage metrics with pricing table and use shell-safe org-id placeholder 2026-07-27 15:18:55 -07:00
Lyu 9f3317e9e6 fix(auth): harden email OTP sign-in per review
Security
- Add an otp_type discriminator to auth.email_otps and scope numeric-code
  verification to NUMERIC_CODE rows, so a wrong 6-digit guess can no longer
  consume a live magic-link (HASH_TOKEN) reset/verify token for the same
  (email, purpose).
- Case-insensitive user lookup in signInWithOTP so a mixed-case OAuth email
  no longer creates a duplicate lowercased account.
- Re-sanitize non-AppError failures in the OTP verify paths (no raw infra
  error messages in 500 responses).

Refactor
- AuthOTPService.consumeNumericOTP owns the OTP transaction: it persists the
  attempt counter on failure, commits caller work + consumption together, and
  rolls back on caller error. signInWithOTP, verifyEmailWithCode and
  exchangeCodeForToken route through it; remove the dead verifyEmailOTPWithCode.
- Resolve disableSignup via AuthConfigService; STRING_AGG(DISTINCT) providers
  and drop the user_id reassignment in the email provider upsert; reuse
  EMAIL_TEMPLATE_TYPES in the cloud provider.

Schema / contract / docs
- Session preprocess treats null/undefined method as the legacy password flow;
  shared six-digit code schema; trim name before the length check.
- Add request-otp to the OpenAPI email-template enum; document the
  unverified-account password-clearing behavior in the four REST guides.

Tests updated/added across the OTP service, route, schema, and migration suites.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-27 11:41:19 -07:00
mintlify[bot] 743d2ad94d docs: improve SEO description for Email SDK reference (#1809)
Check Migrations / Check for duplicate migration numbers (push) Has been cancelled
CI Pre-merge Check / CI Pre-merge Check (push) Has been cancelled
Lint and Format Check / lint-and-format (push) Has been cancelled
Co-authored-by: mintlify[bot] <109931778+mintlify[bot]@users.noreply.github.com>
2026-07-27 02:59:18 +00:00