A Gitea project consists of a git repository and rows stored in a SQL database to represent the description of the project, issues, milestones, pull requests, etc. The entire database and the tables that contain these rows are created by xorm from definitions from in the models directory for issues, repository, etc.
The Gitea API is JSON based. The endpoint to create an issue expects a JSON description of the issue from the structs directory that defines the CreateIssueOption. It is also in the same structs directory that the Issue data structure will be found and converted from the data found in the database before it is returned from the endpoint to get the full information about an issue.
When migrating a project to or from Gitea, the information it contains is stored in data structures dedicated to migration by the downloader (for issues, etc.). There exist downloader implementations for GitLab, GitHub, etc. These data structures are then fed to an uploader to re-create / migrate the project from scratch. There currently exists only one uploader for Gitea.
The migration can use the originating forge API to obtain information in memory using the downloader and send it to the uploader. It can also dump the information obtained by the downloader to disk in YAML, and, at a later time, read the YAML files and feed them to the uploader.
To summarize the above, the following paths exist to transform data structures in Gitea. Not all data structures representing a particular aspect of a project contain the same information. For instance in the case of an issue the migration data structure have much less information than the model data structure. It is however possible to transform each data structure into another (in some cases via an intermediary representation, for instance when dumping a project that resides in the database into migration files it is done via the API).