docs: introduce versioned docs and migrate to fuma (#11166)

## Todos for release

- [x] Configure Env in docs project on vercel
- [x] Configure Root Path in the docs project on vercel
- [ ] Remove old CSP https://github.com/zitadel/website/pull/1592

## What we did

This pull request migrates the project documentation from the old
`docs/` directory to the new `apps/docs/` directory, introduces a new
documentation system built with Next.js and Fumadocs, and updates all
relevant references, configuration files, and documentation to reflect
this change. It also adds new configuration and ignore files for the new
documentation app, updates CI and linting to exclude the new docs from
certain checks, and revises the contributing guidelines accordingly.

**Documentation System Migration and New Docs App**

* Migrated all documentation from `docs/` to `apps/docs/`, and updated
all references in `README.md`, `CONTRIBUTING.md`, and other files to
point to the new location.
[[1]](diffhunk://#diff-eca12c0a30e25b4b46522ebf89465a03ba72a03f540796c979137931d8f92055L585-L640)
[[2]](diffhunk://#diff-eca12c0a30e25b4b46522ebf89465a03ba72a03f540796c979137931d8f92055L660-R607)
[[3]](diffhunk://#diff-eca12c0a30e25b4b46522ebf89465a03ba72a03f540796c979137931d8f92055L740-R687)
[[4]](diffhunk://#diff-b335630551682c19a781afebcf4d07bf978fb1f8ac04c6bf87428ed5106870f5L2-R3)
[[5]](diffhunk://#diff-b335630551682c19a781afebcf4d07bf978fb1f8ac04c6bf87428ed5106870f5L30-R30)
* Added a new Next.js/Fumadocs-based documentation app under
`apps/docs/`, including core app files, layouts, routing, search API,
and a comprehensive `README.md` with development and contribution
instructions.
[[1]](diffhunk://#diff-5a1b07344a2c1b4d3f37b23ff1388b62cd9f57dea3c1cd23d8a0412b7602b132R1-R74)
[[2]](diffhunk://#diff-462b9ad1eabbb7d1c29bb9c36e4931eb180fd7190900e6d2babf8f4d66ad1c28R1-R39)
[[3]](diffhunk://#diff-e16ae25660ded787b10ac35dea96d5ecaacf895dae0afc8a9bd4382dc79a8c87R1-R7)
[apps/docs/app/[[...slug]]/layout.tsxR1-R81](diffhunk://#diff-59e08acde4e805b7aeccef1dcf98f1d71dfc550777e6b9402085cee0e9fa4e0aR1-R81),
[apps/docs/app/[[...slug]]/page.tsxR1-R79](diffhunk://#diff-e5df3f80d0fa01e12d63d81f29c57a9d14e846c78fd3beabb2ef768e38fd9580R1-R79),
[[4]](diffhunk://#diff-389b34918e040cacaa87cd7201ffa462cc2b0b716736f537e3d3c660ac69353bR1-R7)
[[5]](diffhunk://#diff-d3b03416d1c457b19f1c27b26f2db741412df841b875c26ccadc36e4522247f4R1-R29)
[[6]](diffhunk://#diff-c8fb8339570a5305809be7c618e14705fd86390dc278e6ce8ba224a7bc8b0c3cR1-R25)

**Configuration and Tooling Updates**

* Updated `.github/workflows/codeql.yml`, `.golangci.yaml`, and
`.github/dependabot.yml` to properly handle the new docs app: excluded
`apps/docs` from certain checks, added npm dependency updates for the
docs app, and excluded generated content.
[[1]](diffhunk://#diff-12783128521e452af0cfac94b99b8d250413c516ec71fe6d97dbea666ff7ba27L8-R14)
[[2]](diffhunk://#diff-9917ddc9f1c3304218f7269265b746d997c5c0615478177b5fceecd33ef47cb5R5-R6)
[[3]](diffhunk://#diff-9917ddc9f1c3304218f7269265b746d997c5c0615478177b5fceecd33ef47cb5R126-R129)
[[4]](diffhunk://#diff-dd4fbda47e51f1e35defb9275a9cd9c212ecde0b870cba89ddaaae65c5f3cd28R89-R106)
* Updated `.devcontainer/devcontainer.json` to use the latest Go 1.25.3
version for consistency.

**Licensing and Miscellaneous**

* Added `apps/docs/` to the list of licensed directories in
`LICENSING.md`.

These changes ensure the documentation is now maintained in a modern,
scalable system and all project tooling is updated to support the new
structure.

---------

Co-authored-by: Federico Coppede <[email protected]>
This commit is contained in:
Florian Forster
2026-01-29 08:38:36 -08:00
committed by GitHub
co-authored by Federico Coppede
parent 7b6395c348
commit d8ea041c56
2826 changed files with 78739 additions and 23571 deletions
@@ -0,0 +1,196 @@
---
title: Migrate from ZITADEL
sidebar_label: From ZITADEL
---
This guide explains how to migrate from ZITADEL, this includes
- ZITADEL Cloud to self-hosted
- ZITADEL self-hosted to ZITADEL Cloud
- ZITADEL v1 (deprecated) to ZITADEL v2.x
## Considerations
The following scripts don't include:
- Global policies
- IAM members
- Global IDPs
- Global second factor / multi-factors
- Machine keys
- Personal Access Tokens
- Application keys
- Passkey authentication
Which results in that if you want to import, and you have no defined organization-specific custom policies, the experience for your users will not be exactly like in your old instance.
<Callout>
Note that the resources will be migrated without the event stream. This means that you will not have the audit trail for the imported objects.
</Callout>
## Authorization
You need a PAT from a service user with IAM Owner permissions in both the source and target system.
### Source system
1. Go to your default organization
2. Create a service user "import_user" with Access Token Type "Bearer"
3. Create a [personal access token](/guides/integrate/service-users/personal-access-token)
4. Go to the Default settings
5. Add the import_user as [manager](/guides/manage/console/managers) with the role "IAM Owner"
Save the PAT to the environment variable `PAT_EXPORT_TOKEN` and the source domain as `ZITADEL_EXPORT_DOMAIN` to run the following scripts.
### Target system
1. Go to your default organization
2. Create a service user "export_user" with Access Token Type "Bearer"
3. Create a [personal access token](/guides/integrate/service-users/personal-access-token)
4. Go to the Default settings
5. Add the export_user as [manager](/guides/manage/console/managers) with the role "IAM Owner"
Save the PAT to the environment variable `PAT_IMPORT_TOKEN` and the source domain as `ZITADEL_IMPORT_DOMAIN` to run the following scripts.
<Callout title="Clean-up">
You should let the PAT expire as soon as possible.
Make sure to delete the created users after you are done with the migration.
</Callout>
## Use file
### Export to file
To export all necessary data you only have to use one request, as an example:
```bash
curl --request POST \
--url $ZITADEL_EXPORT_DOMAIN/admin/v1/export \
--header "Authorization: Bearer $PAT_EXPORT_TOKEN" \
--header 'Content-Type: application/json' \
--data '{
"org_ids": [ ],
"excluded_org_ids": [ ],
"with_passwords": true,
"with_otp": true,
"timeout": "30s",
"response_output": true
}' -o export.json
```
| Field | Type | Description |
| ---------------- | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| org_ids | list of strings | provide a list of Organization IDs to select which organizations should be exported (eg, `[ "70669144072186707", "70671105999825752" ]`); leave empty to export all |
| excluded_org_ids | list of strings | to exclude several organization, if for example no organizations are selected |
| with_passwords | bool | to include the hashed_passwords of the users in the export |
| with_otp | bool | to include the OTP-code of the users in the export |
| timeout | duration string | timeout of the call to export the data |
| response_output | bool | to output the export as response to the call |
### Import from file
<Callout>
To import the exported data into you new instance, you have to have an already existing instance on a ZITADEL, with all desired configuration and global resources.
</Callout>
Then as an example you can use one request for the import:
```bash
curl --request POST \
--url $ZITADEL_IMPORT_DOMAIN/admin/v1/import \
--header "Authorization: Bearer $PAT_IMPORT_TOKEN" \
--header 'Content-Type: application/json' \
--data '{
"timeout": "10m",
"data_orgsv1": '"$(cat export.json)"'
}'
```
| Field | Type | Description |
| ----------- | --------------- | --------------------------------------- |
| timeout | duration string | timeout of the call to import the data |
| data_orgsv1 | string | data which was exported from ZITADEL V1 |
## Use Google Cloud Storage
### Export to GCS
<Callout>
To use this requests you have to have an access token with enough permissions to export and import.
The used serviceaccount has to have at least the role "Storage Object Creator" to create objects on GCS
</Callout>
To export all necessary data you only have to use one request which results in a file in your GCS, as an example:
```bash
curl --request POST \
--url $ZITADEL_EXPORT_DOMAIN/admin/v1/export \
--header "Authorization: Bearer $PAT_EXPORT_TOKEN" \
--header 'Content-Type: application/json' \
--data '{
"org_ids": [ ],
"excluded_org_ids": [ ],
"with_passwords": true,
"with_otp": true,
"timeout": "30s",
"gcs_output": {
"path": "export.json",
"bucket": "caos-zitadel-exports",
"serviceaccount_json": "XXXX"
}
}' -o export.json
```
| Field | Type | Description |
| ---------------- | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| org_ids | list of strings | provide a list of Organization IDs to select which organizations should be exported (eg, `[ "70669144072186707", "70671105999825752" ]`); leave empty to export all |
| excluded_org_ids | list of strings | to exclude several organization, if for example no organizations are selected |
| with_passwords | bool | to include the hashed_passwords of the users in the export |
| with_otp | bool | to include the OTP-code of the users in the export |
| timeout | duration string | timeout of the call to export the data |
| gcs_output | object(data_orgsv1_gcs) | to write a file into GCS as output to the call |
data_orgsv1_gcs object:
| Field | Type | Description |
| ------------------- | ------ | ----------------------------------------------------------------- |
| path | string | path to the output file on GCS |
| bucket | string | used bucket for output on GCS |
| serviceaccount_json | string | base64-encoded serviceaccount.json used to output the file on GCS |
### Import to GCS
<Callout>
To import the exported data into you new instance, you have to have an already existing instance on a ZITADEL, with all desired configuration and global resources.
The used serviceaccount has to have at least the role "Storage Object Viewer" to read objects from GCS
</Callout>
Then as an example you can use one request for the import:
```bash
curl --request POST \
--url $ZITADEL_IMPORT_DOMAIN/admin/v1/import \
--header "Authorization: Bearer $PAT_IMPORT_TOKEN" \
--header 'Content-Type: application/json' \
--data '{
"timeout": "10m",
"data_orgsv1_gcs": {
"path": "export.json",
"bucket": "caos-zitadel-exports",
"serviceaccount_json": "XXXX"
}
}'
```
| Field | Type | Description |
| --------------- | ----------------------- | -------------------------------------- |
| timeout | duration string | timeout of the call to import the data |
| data_orgsv1_gcs | object(data_orgsv1_gcs) | to read the export from GCS directly |
data_orgsv1_gcs object:
| Field | Type | Description |
| ------------------- | ------ | ----------------------------------------------------------------- |
| path | string | path to the exported file on GCS |
| bucket | string | used bucket to read from GCS |
| serviceaccount_json | string | base64-encoded serviceaccount.json used to read the file from GCS |