diff --git a/models/activities/action.go b/models/activities/action.go
index 65d95fbe66..ff7fdb2f10 100644
--- a/models/activities/action.go
+++ b/models/activities/action.go
@@ -511,7 +511,7 @@ func ActivityQueryCondition(ctx context.Context, opts GetFeedsOptions) (builder.
 	}
 
 	if opts.RequestedTeam != nil {
-		env := organization.OrgFromUser(opts.RequestedUser).AccessibleTeamReposEnv(ctx, opts.RequestedTeam)
+		env := repo_model.AccessibleTeamReposEnv(ctx, organization.OrgFromUser(opts.RequestedUser), opts.RequestedTeam)
 		teamRepoIDs, err := env.RepoIDs(1, opts.RequestedUser.NumRepos)
 		if err != nil {
 			return nil, fmt.Errorf("GetTeamRepositories: %w", err)
diff --git a/models/error.go b/models/error.go
index 75c53245de..865d5a442f 100644
--- a/models/error.go
+++ b/models/error.go
@@ -72,48 +72,6 @@ func (err ErrDeleteLastAdminUser) Error() string {
 	return fmt.Sprintf("can not delete the last admin user [uid: %d]", err.UID)
 }
 
-// ErrNoPendingRepoTransfer is an error type for repositories without a pending
-// transfer request
-type ErrNoPendingRepoTransfer struct {
-	RepoID int64
-}
-
-func (err ErrNoPendingRepoTransfer) Error() string {
-	return fmt.Sprintf("repository doesn't have a pending transfer [repo_id: %d]", err.RepoID)
-}
-
-// IsErrNoPendingTransfer is an error type when a repository has no pending
-// transfers
-func IsErrNoPendingTransfer(err error) bool {
-	_, ok := err.(ErrNoPendingRepoTransfer)
-	return ok
-}
-
-func (err ErrNoPendingRepoTransfer) Unwrap() error {
-	return util.ErrNotExist
-}
-
-// ErrRepoTransferInProgress represents the state of a repository that has an
-// ongoing transfer
-type ErrRepoTransferInProgress struct {
-	Uname string
-	Name  string
-}
-
-// IsErrRepoTransferInProgress checks if an error is a ErrRepoTransferInProgress.
-func IsErrRepoTransferInProgress(err error) bool {
-	_, ok := err.(ErrRepoTransferInProgress)
-	return ok
-}
-
-func (err ErrRepoTransferInProgress) Error() string {
-	return fmt.Sprintf("repository is already being transferred [uname: %s, name: %s]", err.Uname, err.Name)
-}
-
-func (err ErrRepoTransferInProgress) Unwrap() error {
-	return util.ErrAlreadyExist
-}
-
 // ErrInvalidCloneAddr represents a "InvalidCloneAddr" kind of error.
 type ErrInvalidCloneAddr struct {
 	Host               string
diff --git a/models/organization/org.go b/models/organization/org.go
index 725a99356e..3e55a36758 100644
--- a/models/organization/org.go
+++ b/models/organization/org.go
@@ -9,11 +9,8 @@ import (
 	"fmt"
 	"strings"
 
-	actions_model "code.gitea.io/gitea/models/actions"
 	"code.gitea.io/gitea/models/db"
 	"code.gitea.io/gitea/models/perm"
-	repo_model "code.gitea.io/gitea/models/repo"
-	secret_model "code.gitea.io/gitea/models/secret"
 	"code.gitea.io/gitea/models/unit"
 	user_model "code.gitea.io/gitea/models/user"
 	"code.gitea.io/gitea/modules/log"
@@ -407,33 +404,6 @@ func GetOrgByName(ctx context.Context, name string) (*Organization, error) {
 	return u, nil
 }
 
-// DeleteOrganization deletes models associated to an organization.
-func DeleteOrganization(ctx context.Context, org *Organization) error {
-	if org.Type != user_model.UserTypeOrganization {
-		return fmt.Errorf("%s is a user not an organization", org.Name)
-	}
-
-	if err := db.DeleteBeans(ctx,
-		&Team{OrgID: org.ID},
-		&OrgUser{OrgID: org.ID},
-		&TeamUser{OrgID: org.ID},
-		&TeamUnit{OrgID: org.ID},
-		&TeamInvite{OrgID: org.ID},
-		&secret_model.Secret{OwnerID: org.ID},
-		&user_model.Blocking{BlockerID: org.ID},
-		&actions_model.ActionRunner{OwnerID: org.ID},
-		&actions_model.ActionRunnerToken{OwnerID: org.ID},
-	); err != nil {
-		return fmt.Errorf("DeleteBeans: %w", err)
-	}
-
-	if _, err := db.GetEngine(ctx).ID(org.ID).Delete(new(user_model.User)); err != nil {
-		return fmt.Errorf("Delete: %w", err)
-	}
-
-	return nil
-}
-
 // GetOrgUserMaxAuthorizeLevel returns highest authorize level of user in an organization
 func (org *Organization) GetOrgUserMaxAuthorizeLevel(ctx context.Context, uid int64) (perm.AccessMode, error) {
 	var authorize perm.AccessMode
@@ -604,7 +574,9 @@ func RemoveOrgRepo(ctx context.Context, orgID, repoID int64) error {
 	return err
 }
 
-func (org *Organization) getUserTeams(ctx context.Context, userID int64, cols ...string) ([]*Team, error) {
+// GetUserTeams returns all teams that belong to user,
+// and that the user has joined.
+func (org *Organization) GetUserTeams(ctx context.Context, userID int64, cols ...string) ([]*Team, error) {
 	teams := make([]*Team, 0, org.NumTeams)
 	return teams, db.GetEngine(ctx).
 		Where("`team_user`.org_id = ?", org.ID).
@@ -616,7 +588,8 @@ func (org *Organization) getUserTeams(ctx context.Context, userID int64, cols ..
 		Find(&teams)
 }
 
-func (org *Organization) getUserTeamIDs(ctx context.Context, userID int64) ([]int64, error) {
+// GetUserTeamIDs returns of all team IDs of the organization that user is member of.
+func (org *Organization) GetUserTeamIDs(ctx context.Context, userID int64) ([]int64, error) {
 	teamIDs := make([]int64, 0, org.NumTeams)
 	return teamIDs, db.GetEngine(ctx).
 		Table("team").
@@ -640,175 +613,3 @@ func getUserTeamIDsQueryBuilder(orgID, userID int64) *builder.Builder {
 func (org *Organization) TeamsWithAccessToRepo(ctx context.Context, repoID int64, mode perm.AccessMode) ([]*Team, error) {
 	return GetTeamsWithAccessToRepo(ctx, org.ID, repoID, mode)
 }
-
-// GetUserTeamIDs returns of all team IDs of the organization that user is member of.
-func (org *Organization) GetUserTeamIDs(ctx context.Context, userID int64) ([]int64, error) {
-	return org.getUserTeamIDs(ctx, userID)
-}
-
-// GetUserTeams returns all teams that belong to user,
-// and that the user has joined.
-func (org *Organization) GetUserTeams(ctx context.Context, userID int64) ([]*Team, error) {
-	return org.getUserTeams(ctx, userID)
-}
-
-// AccessibleReposEnvironment operations involving the repositories that are
-// accessible to a particular user
-type AccessibleReposEnvironment interface {
-	CountRepos() (int64, error)
-	RepoIDs(page, pageSize int) ([]int64, error)
-	Repos(page, pageSize int) (repo_model.RepositoryList, error)
-	MirrorRepos() (repo_model.RepositoryList, error)
-	AddKeyword(keyword string)
-	SetSort(db.SearchOrderBy)
-}
-
-type accessibleReposEnv struct {
-	org     *Organization
-	user    *user_model.User
-	team    *Team
-	teamIDs []int64
-	ctx     context.Context
-	keyword string
-	orderBy db.SearchOrderBy
-}
-
-// AccessibleReposEnv builds an AccessibleReposEnvironment for the repositories in `org`
-// that are accessible to the specified user.
-func AccessibleReposEnv(ctx context.Context, org *Organization, userID int64) (AccessibleReposEnvironment, error) {
-	var user *user_model.User
-
-	if userID > 0 {
-		u, err := user_model.GetUserByID(ctx, userID)
-		if err != nil {
-			return nil, err
-		}
-		user = u
-	}
-
-	teamIDs, err := org.getUserTeamIDs(ctx, userID)
-	if err != nil {
-		return nil, err
-	}
-	return &accessibleReposEnv{
-		org:     org,
-		user:    user,
-		teamIDs: teamIDs,
-		ctx:     ctx,
-		orderBy: db.SearchOrderByRecentUpdated,
-	}, nil
-}
-
-// AccessibleTeamReposEnv an AccessibleReposEnvironment for the repositories in `org`
-// that are accessible to the specified team.
-func (org *Organization) AccessibleTeamReposEnv(ctx context.Context, team *Team) AccessibleReposEnvironment {
-	return &accessibleReposEnv{
-		org:     org,
-		team:    team,
-		ctx:     ctx,
-		orderBy: db.SearchOrderByRecentUpdated,
-	}
-}
-
-func (env *accessibleReposEnv) cond() builder.Cond {
-	cond := builder.NewCond()
-	if env.team != nil {
-		cond = cond.And(builder.Eq{"team_repo.team_id": env.team.ID})
-	} else {
-		if env.user == nil || !env.user.IsRestricted {
-			cond = cond.Or(builder.Eq{
-				"`repository`.owner_id":   env.org.ID,
-				"`repository`.is_private": false,
-			})
-		}
-		if len(env.teamIDs) > 0 {
-			cond = cond.Or(builder.In("team_repo.team_id", env.teamIDs))
-		}
-	}
-	if env.keyword != "" {
-		cond = cond.And(builder.Like{"`repository`.lower_name", strings.ToLower(env.keyword)})
-	}
-	return cond
-}
-
-func (env *accessibleReposEnv) CountRepos() (int64, error) {
-	repoCount, err := db.GetEngine(env.ctx).
-		Join("INNER", "team_repo", "`team_repo`.repo_id=`repository`.id").
-		Where(env.cond()).
-		Distinct("`repository`.id").
-		Count(&repo_model.Repository{})
-	if err != nil {
-		return 0, fmt.Errorf("count user repositories in organization: %w", err)
-	}
-	return repoCount, nil
-}
-
-func (env *accessibleReposEnv) RepoIDs(page, pageSize int) ([]int64, error) {
-	if page <= 0 {
-		page = 1
-	}
-
-	repoIDs := make([]int64, 0, pageSize)
-	return repoIDs, db.GetEngine(env.ctx).
-		Table("repository").
-		Join("INNER", "team_repo", "`team_repo`.repo_id=`repository`.id").
-		Where(env.cond()).
-		GroupBy("`repository`.id,`repository`."+strings.Fields(string(env.orderBy))[0]).
-		OrderBy(string(env.orderBy)).
-		Limit(pageSize, (page-1)*pageSize).
-		Cols("`repository`.id").
-		Find(&repoIDs)
-}
-
-func (env *accessibleReposEnv) Repos(page, pageSize int) (repo_model.RepositoryList, error) {
-	repoIDs, err := env.RepoIDs(page, pageSize)
-	if err != nil {
-		return nil, fmt.Errorf("GetUserRepositoryIDs: %w", err)
-	}
-
-	repos := make([]*repo_model.Repository, 0, len(repoIDs))
-	if len(repoIDs) == 0 {
-		return repos, nil
-	}
-
-	return repos, db.GetEngine(env.ctx).
-		In("`repository`.id", repoIDs).
-		OrderBy(string(env.orderBy)).
-		Find(&repos)
-}
-
-func (env *accessibleReposEnv) MirrorRepoIDs() ([]int64, error) {
-	repoIDs := make([]int64, 0, 10)
-	return repoIDs, db.GetEngine(env.ctx).
-		Table("repository").
-		Join("INNER", "team_repo", "`team_repo`.repo_id=`repository`.id AND `repository`.is_mirror=?", true).
-		Where(env.cond()).
-		GroupBy("`repository`.id, `repository`.updated_unix").
-		OrderBy(string(env.orderBy)).
-		Cols("`repository`.id").
-		Find(&repoIDs)
-}
-
-func (env *accessibleReposEnv) MirrorRepos() (repo_model.RepositoryList, error) {
-	repoIDs, err := env.MirrorRepoIDs()
-	if err != nil {
-		return nil, fmt.Errorf("MirrorRepoIDs: %w", err)
-	}
-
-	repos := make([]*repo_model.Repository, 0, len(repoIDs))
-	if len(repoIDs) == 0 {
-		return repos, nil
-	}
-
-	return repos, db.GetEngine(env.ctx).
-		In("`repository`.id", repoIDs).
-		Find(&repos)
-}
-
-func (env *accessibleReposEnv) AddKeyword(keyword string) {
-	env.keyword = keyword
-}
-
-func (env *accessibleReposEnv) SetSort(orderBy db.SearchOrderBy) {
-	env.orderBy = orderBy
-}
diff --git a/models/organization/org_repo.go b/models/organization/org_repo.go
deleted file mode 100644
index f7e59928f4..0000000000
--- a/models/organization/org_repo.go
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2022 The Gitea Authors. All rights reserved.
-// SPDX-License-Identifier: MIT
-
-package organization
-
-import (
-	"context"
-
-	"code.gitea.io/gitea/models/db"
-	repo_model "code.gitea.io/gitea/models/repo"
-)
-
-// GetOrgRepositories get repos belonging to the given organization
-func GetOrgRepositories(ctx context.Context, orgID int64) (repo_model.RepositoryList, error) {
-	var orgRepos []*repo_model.Repository
-	return orgRepos, db.GetEngine(ctx).Where("owner_id = ?", orgID).Find(&orgRepos)
-}
diff --git a/models/organization/org_test.go b/models/organization/org_test.go
index 5e99e88689..2c5b4090df 100644
--- a/models/organization/org_test.go
+++ b/models/organization/org_test.go
@@ -318,7 +318,7 @@ func TestAccessibleReposEnv_CountRepos(t *testing.T) {
 	assert.NoError(t, unittest.PrepareTestDatabase())
 	org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3})
 	testSuccess := func(userID, expectedCount int64) {
-		env, err := organization.AccessibleReposEnv(db.DefaultContext, org, userID)
+		env, err := repo_model.AccessibleReposEnv(db.DefaultContext, org, userID)
 		assert.NoError(t, err)
 		count, err := env.CountRepos()
 		assert.NoError(t, err)
@@ -332,7 +332,7 @@ func TestAccessibleReposEnv_RepoIDs(t *testing.T) {
 	assert.NoError(t, unittest.PrepareTestDatabase())
 	org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3})
 	testSuccess := func(userID int64, expectedRepoIDs []int64) {
-		env, err := organization.AccessibleReposEnv(db.DefaultContext, org, userID)
+		env, err := repo_model.AccessibleReposEnv(db.DefaultContext, org, userID)
 		assert.NoError(t, err)
 		repoIDs, err := env.RepoIDs(1, 100)
 		assert.NoError(t, err)
@@ -346,7 +346,7 @@ func TestAccessibleReposEnv_Repos(t *testing.T) {
 	assert.NoError(t, unittest.PrepareTestDatabase())
 	org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3})
 	testSuccess := func(userID int64, expectedRepoIDs []int64) {
-		env, err := organization.AccessibleReposEnv(db.DefaultContext, org, userID)
+		env, err := repo_model.AccessibleReposEnv(db.DefaultContext, org, userID)
 		assert.NoError(t, err)
 		repos, err := env.Repos(1, 100)
 		assert.NoError(t, err)
@@ -365,7 +365,7 @@ func TestAccessibleReposEnv_MirrorRepos(t *testing.T) {
 	assert.NoError(t, unittest.PrepareTestDatabase())
 	org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3})
 	testSuccess := func(userID int64, expectedRepoIDs []int64) {
-		env, err := organization.AccessibleReposEnv(db.DefaultContext, org, userID)
+		env, err := repo_model.AccessibleReposEnv(db.DefaultContext, org, userID)
 		assert.NoError(t, err)
 		repos, err := env.MirrorRepos()
 		assert.NoError(t, err)
diff --git a/models/organization/team.go b/models/organization/team.go
index fb7f0c0493..96666da39a 100644
--- a/models/organization/team.go
+++ b/models/organization/team.go
@@ -11,7 +11,6 @@ import (
 
 	"code.gitea.io/gitea/models/db"
 	"code.gitea.io/gitea/models/perm"
-	repo_model "code.gitea.io/gitea/models/repo"
 	"code.gitea.io/gitea/models/unit"
 	user_model "code.gitea.io/gitea/models/user"
 	"code.gitea.io/gitea/modules/log"
@@ -78,9 +77,8 @@ type Team struct {
 	LowerName               string
 	Name                    string
 	Description             string
-	AccessMode              perm.AccessMode          `xorm:"'authorize'"`
-	Repos                   []*repo_model.Repository `xorm:"-"`
-	Members                 []*user_model.User       `xorm:"-"`
+	AccessMode              perm.AccessMode    `xorm:"'authorize'"`
+	Members                 []*user_model.User `xorm:"-"`
 	NumRepos                int
 	NumMembers              int
 	Units                   []*TeamUnit `xorm:"-"`
@@ -155,17 +153,6 @@ func (t *Team) IsMember(ctx context.Context, userID int64) bool {
 	return isMember
 }
 
-// LoadRepositories returns paginated repositories in team of organization.
-func (t *Team) LoadRepositories(ctx context.Context) (err error) {
-	if t.Repos != nil {
-		return nil
-	}
-	t.Repos, err = GetTeamRepositories(ctx, &SearchTeamRepoOptions{
-		TeamID: t.ID,
-	})
-	return err
-}
-
 // LoadMembers returns paginated members in team of organization.
 func (t *Team) LoadMembers(ctx context.Context) (err error) {
 	t.Members, err = GetTeamMembers(ctx, &SearchMembersOptions{
diff --git a/models/organization/team_list.go b/models/organization/team_list.go
index 4ceb405e31..6f2a922e95 100644
--- a/models/organization/team_list.go
+++ b/models/organization/team_list.go
@@ -9,7 +9,6 @@ import (
 
 	"code.gitea.io/gitea/models/db"
 	"code.gitea.io/gitea/models/perm"
-	repo_model "code.gitea.io/gitea/models/repo"
 	"code.gitea.io/gitea/models/unit"
 
 	"xorm.io/builder"
@@ -98,11 +97,11 @@ func SearchTeam(ctx context.Context, opts *SearchTeamOptions) (TeamList, int64,
 }
 
 // GetRepoTeams gets the list of teams that has access to the repository
-func GetRepoTeams(ctx context.Context, repo *repo_model.Repository) (teams TeamList, err error) {
+func GetRepoTeams(ctx context.Context, orgID, repoID int64) (teams TeamList, err error) {
 	return teams, db.GetEngine(ctx).
 		Join("INNER", "team_repo", "team_repo.team_id = team.id").
-		Where("team.org_id = ?", repo.OwnerID).
-		And("team_repo.repo_id=?", repo.ID).
+		Where("team.org_id = ?", orgID).
+		And("team_repo.repo_id=?", repoID).
 		OrderBy("CASE WHEN name LIKE '" + OwnerTeamName + "' THEN '' ELSE name END").
 		Find(&teams)
 }
diff --git a/models/organization/team_repo.go b/models/organization/team_repo.go
index c90dfdeda0..53edd203a8 100644
--- a/models/organization/team_repo.go
+++ b/models/organization/team_repo.go
@@ -8,10 +8,7 @@ import (
 
 	"code.gitea.io/gitea/models/db"
 	"code.gitea.io/gitea/models/perm"
-	repo_model "code.gitea.io/gitea/models/repo"
 	"code.gitea.io/gitea/models/unit"
-
-	"xorm.io/builder"
 )
 
 // TeamRepo represents an team-repository relation.
@@ -32,29 +29,6 @@ func HasTeamRepo(ctx context.Context, orgID, teamID, repoID int64) bool {
 	return has
 }
 
-type SearchTeamRepoOptions struct {
-	db.ListOptions
-	TeamID int64
-}
-
-// GetRepositories returns paginated repositories in team of organization.
-func GetTeamRepositories(ctx context.Context, opts *SearchTeamRepoOptions) (repo_model.RepositoryList, error) {
-	sess := db.GetEngine(ctx)
-	if opts.TeamID > 0 {
-		sess = sess.In("id",
-			builder.Select("repo_id").
-				From("team_repo").
-				Where(builder.Eq{"team_id": opts.TeamID}),
-		)
-	}
-	if opts.PageSize > 0 {
-		sess.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize)
-	}
-	var repos []*repo_model.Repository
-	return repos, sess.OrderBy("repository.name").
-		Find(&repos)
-}
-
 // AddTeamRepo adds a repo for an organization's team
 func AddTeamRepo(ctx context.Context, orgID, teamID, repoID int64) error {
 	_, err := db.GetEngine(ctx).Insert(&TeamRepo{
diff --git a/models/organization/team_test.go b/models/organization/team_test.go
index 8c34e7a612..deaabbfa2c 100644
--- a/models/organization/team_test.go
+++ b/models/organization/team_test.go
@@ -8,6 +8,7 @@ import (
 
 	"code.gitea.io/gitea/models/db"
 	"code.gitea.io/gitea/models/organization"
+	repo_model "code.gitea.io/gitea/models/repo"
 	"code.gitea.io/gitea/models/unittest"
 
 	"github.com/stretchr/testify/assert"
@@ -42,9 +43,12 @@ func TestTeam_GetRepositories(t *testing.T) {
 
 	test := func(teamID int64) {
 		team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID})
-		assert.NoError(t, team.LoadRepositories(db.DefaultContext))
-		assert.Len(t, team.Repos, team.NumRepos)
-		for _, repo := range team.Repos {
+		repos, err := repo_model.GetTeamRepositories(db.DefaultContext, &repo_model.SearchTeamRepoOptions{
+			TeamID: team.ID,
+		})
+		assert.NoError(t, err)
+		assert.Len(t, repos, team.NumRepos)
+		for _, repo := range repos {
 			unittest.AssertExistsAndLoadBean(t, &organization.TeamRepo{TeamID: teamID, RepoID: repo.ID})
 		}
 	}
diff --git a/models/repo/org_repo.go b/models/repo/org_repo.go
new file mode 100644
index 0000000000..5f0af2d475
--- /dev/null
+++ b/models/repo/org_repo.go
@@ -0,0 +1,206 @@
+// Copyright 2022 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package repo
+
+import (
+	"context"
+	"fmt"
+	"strings"
+
+	"code.gitea.io/gitea/models/db"
+	org_model "code.gitea.io/gitea/models/organization"
+	user_model "code.gitea.io/gitea/models/user"
+
+	"xorm.io/builder"
+)
+
+// GetOrgRepositories get repos belonging to the given organization
+func GetOrgRepositories(ctx context.Context, orgID int64) (RepositoryList, error) {
+	var orgRepos []*Repository
+	return orgRepos, db.GetEngine(ctx).Where("owner_id = ?", orgID).Find(&orgRepos)
+}
+
+type SearchTeamRepoOptions struct {
+	db.ListOptions
+	TeamID int64
+}
+
+// GetRepositories returns paginated repositories in team of organization.
+func GetTeamRepositories(ctx context.Context, opts *SearchTeamRepoOptions) (RepositoryList, error) {
+	sess := db.GetEngine(ctx)
+	if opts.TeamID > 0 {
+		sess = sess.In("id",
+			builder.Select("repo_id").
+				From("team_repo").
+				Where(builder.Eq{"team_id": opts.TeamID}),
+		)
+	}
+	if opts.PageSize > 0 {
+		sess.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize)
+	}
+	var repos []*Repository
+	return repos, sess.OrderBy("repository.name").
+		Find(&repos)
+}
+
+// AccessibleReposEnvironment operations involving the repositories that are
+// accessible to a particular user
+type AccessibleReposEnvironment interface {
+	CountRepos() (int64, error)
+	RepoIDs(page, pageSize int) ([]int64, error)
+	Repos(page, pageSize int) (RepositoryList, error)
+	MirrorRepos() (RepositoryList, error)
+	AddKeyword(keyword string)
+	SetSort(db.SearchOrderBy)
+}
+
+type accessibleReposEnv struct {
+	org     *org_model.Organization
+	user    *user_model.User
+	team    *org_model.Team
+	teamIDs []int64
+	ctx     context.Context
+	keyword string
+	orderBy db.SearchOrderBy
+}
+
+// AccessibleReposEnv builds an AccessibleReposEnvironment for the repositories in `org`
+// that are accessible to the specified user.
+func AccessibleReposEnv(ctx context.Context, org *org_model.Organization, userID int64) (AccessibleReposEnvironment, error) {
+	var user *user_model.User
+
+	if userID > 0 {
+		u, err := user_model.GetUserByID(ctx, userID)
+		if err != nil {
+			return nil, err
+		}
+		user = u
+	}
+
+	teamIDs, err := org.GetUserTeamIDs(ctx, userID)
+	if err != nil {
+		return nil, err
+	}
+	return &accessibleReposEnv{
+		org:     org,
+		user:    user,
+		teamIDs: teamIDs,
+		ctx:     ctx,
+		orderBy: db.SearchOrderByRecentUpdated,
+	}, nil
+}
+
+// AccessibleTeamReposEnv an AccessibleReposEnvironment for the repositories in `org`
+// that are accessible to the specified team.
+func AccessibleTeamReposEnv(ctx context.Context, org *org_model.Organization, team *org_model.Team) AccessibleReposEnvironment {
+	return &accessibleReposEnv{
+		org:     org,
+		team:    team,
+		ctx:     ctx,
+		orderBy: db.SearchOrderByRecentUpdated,
+	}
+}
+
+func (env *accessibleReposEnv) cond() builder.Cond {
+	cond := builder.NewCond()
+	if env.team != nil {
+		cond = cond.And(builder.Eq{"team_repo.team_id": env.team.ID})
+	} else {
+		if env.user == nil || !env.user.IsRestricted {
+			cond = cond.Or(builder.Eq{
+				"`repository`.owner_id":   env.org.ID,
+				"`repository`.is_private": false,
+			})
+		}
+		if len(env.teamIDs) > 0 {
+			cond = cond.Or(builder.In("team_repo.team_id", env.teamIDs))
+		}
+	}
+	if env.keyword != "" {
+		cond = cond.And(builder.Like{"`repository`.lower_name", strings.ToLower(env.keyword)})
+	}
+	return cond
+}
+
+func (env *accessibleReposEnv) CountRepos() (int64, error) {
+	repoCount, err := db.GetEngine(env.ctx).
+		Join("INNER", "team_repo", "`team_repo`.repo_id=`repository`.id").
+		Where(env.cond()).
+		Distinct("`repository`.id").
+		Count(&Repository{})
+	if err != nil {
+		return 0, fmt.Errorf("count user repositories in organization: %w", err)
+	}
+	return repoCount, nil
+}
+
+func (env *accessibleReposEnv) RepoIDs(page, pageSize int) ([]int64, error) {
+	if page <= 0 {
+		page = 1
+	}
+
+	repoIDs := make([]int64, 0, pageSize)
+	return repoIDs, db.GetEngine(env.ctx).
+		Table("repository").
+		Join("INNER", "team_repo", "`team_repo`.repo_id=`repository`.id").
+		Where(env.cond()).
+		GroupBy("`repository`.id,`repository`."+strings.Fields(string(env.orderBy))[0]).
+		OrderBy(string(env.orderBy)).
+		Limit(pageSize, (page-1)*pageSize).
+		Cols("`repository`.id").
+		Find(&repoIDs)
+}
+
+func (env *accessibleReposEnv) Repos(page, pageSize int) (RepositoryList, error) {
+	repoIDs, err := env.RepoIDs(page, pageSize)
+	if err != nil {
+		return nil, fmt.Errorf("GetUserRepositoryIDs: %w", err)
+	}
+
+	repos := make([]*Repository, 0, len(repoIDs))
+	if len(repoIDs) == 0 {
+		return repos, nil
+	}
+
+	return repos, db.GetEngine(env.ctx).
+		In("`repository`.id", repoIDs).
+		OrderBy(string(env.orderBy)).
+		Find(&repos)
+}
+
+func (env *accessibleReposEnv) MirrorRepoIDs() ([]int64, error) {
+	repoIDs := make([]int64, 0, 10)
+	return repoIDs, db.GetEngine(env.ctx).
+		Table("repository").
+		Join("INNER", "team_repo", "`team_repo`.repo_id=`repository`.id AND `repository`.is_mirror=?", true).
+		Where(env.cond()).
+		GroupBy("`repository`.id, `repository`.updated_unix").
+		OrderBy(string(env.orderBy)).
+		Cols("`repository`.id").
+		Find(&repoIDs)
+}
+
+func (env *accessibleReposEnv) MirrorRepos() (RepositoryList, error) {
+	repoIDs, err := env.MirrorRepoIDs()
+	if err != nil {
+		return nil, fmt.Errorf("MirrorRepoIDs: %w", err)
+	}
+
+	repos := make([]*Repository, 0, len(repoIDs))
+	if len(repoIDs) == 0 {
+		return repos, nil
+	}
+
+	return repos, db.GetEngine(env.ctx).
+		In("`repository`.id", repoIDs).
+		Find(&repos)
+}
+
+func (env *accessibleReposEnv) AddKeyword(keyword string) {
+	env.keyword = keyword
+}
+
+func (env *accessibleReposEnv) SetSort(orderBy db.SearchOrderBy) {
+	env.orderBy = orderBy
+}
diff --git a/models/repo_transfer.go b/models/repo/transfer.go
similarity index 73%
rename from models/repo_transfer.go
rename to models/repo/transfer.go
index 37f591f65d..43e15b33bc 100644
--- a/models/repo_transfer.go
+++ b/models/repo/transfer.go
@@ -1,7 +1,7 @@
 // Copyright 2021 The Gitea Authors. All rights reserved.
 // SPDX-License-Identifier: MIT
 
-package models
+package repo
 
 import (
 	"context"
@@ -10,16 +10,58 @@ import (
 
 	"code.gitea.io/gitea/models/db"
 	"code.gitea.io/gitea/models/organization"
-	repo_model "code.gitea.io/gitea/models/repo"
 	user_model "code.gitea.io/gitea/models/user"
 	"code.gitea.io/gitea/modules/log"
 	"code.gitea.io/gitea/modules/timeutil"
+	"code.gitea.io/gitea/modules/util"
 
 	"xorm.io/builder"
 )
 
+// ErrNoPendingRepoTransfer is an error type for repositories without a pending
+// transfer request
+type ErrNoPendingRepoTransfer struct {
+	RepoID int64
+}
+
+func (err ErrNoPendingRepoTransfer) Error() string {
+	return fmt.Sprintf("repository doesn't have a pending transfer [repo_id: %d]", err.RepoID)
+}
+
+// IsErrNoPendingTransfer is an error type when a repository has no pending
+// transfers
+func IsErrNoPendingTransfer(err error) bool {
+	_, ok := err.(ErrNoPendingRepoTransfer)
+	return ok
+}
+
+func (err ErrNoPendingRepoTransfer) Unwrap() error {
+	return util.ErrNotExist
+}
+
+// ErrRepoTransferInProgress represents the state of a repository that has an
+// ongoing transfer
+type ErrRepoTransferInProgress struct {
+	Uname string
+	Name  string
+}
+
+// IsErrRepoTransferInProgress checks if an error is a ErrRepoTransferInProgress.
+func IsErrRepoTransferInProgress(err error) bool {
+	_, ok := err.(ErrRepoTransferInProgress)
+	return ok
+}
+
+func (err ErrRepoTransferInProgress) Error() string {
+	return fmt.Sprintf("repository is already being transferred [uname: %s, name: %s]", err.Uname, err.Name)
+}
+
+func (err ErrRepoTransferInProgress) Unwrap() error {
+	return util.ErrAlreadyExist
+}
+
 // RepoTransfer is used to manage repository transfers
-type RepoTransfer struct {
+type RepoTransfer struct { //nolint
 	ID          int64 `xorm:"pk autoincr"`
 	DoerID      int64
 	Doer        *user_model.User `xorm:"-"`
@@ -126,7 +168,7 @@ func GetPendingRepositoryTransfers(ctx context.Context, opts *PendingRepositoryT
 
 // GetPendingRepositoryTransfer fetches the most recent and ongoing transfer
 // process for the repository
-func GetPendingRepositoryTransfer(ctx context.Context, repo *repo_model.Repository) (*RepoTransfer, error) {
+func GetPendingRepositoryTransfer(ctx context.Context, repo *Repository) (*RepoTransfer, error) {
 	transfers, err := GetPendingRepositoryTransfers(ctx, &PendingRepositoryTransferOptions{RepoID: repo.ID})
 	if err != nil {
 		return nil, err
@@ -145,11 +187,11 @@ func DeleteRepositoryTransfer(ctx context.Context, repoID int64) error {
 }
 
 // TestRepositoryReadyForTransfer make sure repo is ready to transfer
-func TestRepositoryReadyForTransfer(status repo_model.RepositoryStatus) error {
+func TestRepositoryReadyForTransfer(status RepositoryStatus) error {
 	switch status {
-	case repo_model.RepositoryBeingMigrated:
+	case RepositoryBeingMigrated:
 		return errors.New("repo is not ready, currently migrating")
-	case repo_model.RepositoryPendingTransfer:
+	case RepositoryPendingTransfer:
 		return ErrRepoTransferInProgress{}
 	}
 	return nil
@@ -159,7 +201,7 @@ func TestRepositoryReadyForTransfer(status repo_model.RepositoryStatus) error {
 // it marks the repository transfer as "pending"
 func CreatePendingRepositoryTransfer(ctx context.Context, doer, newOwner *user_model.User, repoID int64, teams []*organization.Team) error {
 	return db.WithTx(ctx, func(ctx context.Context) error {
-		repo, err := repo_model.GetRepositoryByID(ctx, repoID)
+		repo, err := GetRepositoryByID(ctx, repoID)
 		if err != nil {
 			return err
 		}
@@ -169,16 +211,16 @@ func CreatePendingRepositoryTransfer(ctx context.Context, doer, newOwner *user_m
 			return err
 		}
 
-		repo.Status = repo_model.RepositoryPendingTransfer
-		if err := repo_model.UpdateRepositoryCols(ctx, repo, "status"); err != nil {
+		repo.Status = RepositoryPendingTransfer
+		if err := UpdateRepositoryCols(ctx, repo, "status"); err != nil {
 			return err
 		}
 
 		// Check if new owner has repository with same name.
-		if has, err := repo_model.IsRepositoryModelExist(ctx, newOwner, repo.Name); err != nil {
+		if has, err := IsRepositoryModelExist(ctx, newOwner, repo.Name); err != nil {
 			return fmt.Errorf("IsRepositoryExist: %w", err)
 		} else if has {
-			return repo_model.ErrRepoAlreadyExist{
+			return ErrRepoAlreadyExist{
 				Uname: newOwner.LowerName,
 				Name:  repo.Name,
 			}
diff --git a/routers/api/v1/org/team.go b/routers/api/v1/org/team.go
index bc50960b61..8164d2cfe9 100644
--- a/routers/api/v1/org/team.go
+++ b/routers/api/v1/org/team.go
@@ -573,19 +573,19 @@ func GetTeamRepos(ctx *context.APIContext) {
 	//     "$ref": "#/responses/notFound"
 
 	team := ctx.Org.Team
-	teamRepos, err := organization.GetTeamRepositories(ctx, &organization.SearchTeamRepoOptions{
+	teamRepos, err := repo_model.GetTeamRepositories(ctx, &repo_model.SearchTeamRepoOptions{
 		ListOptions: utils.GetListOptions(ctx),
 		TeamID:      team.ID,
 	})
 	if err != nil {
-		ctx.Error(http.StatusInternalServerError, "GetTeamRepos", err)
+		ctx.Error(http.StatusInternalServerError, "GetTeamRepositories", err)
 		return
 	}
 	repos := make([]*api.Repository, len(teamRepos))
 	for i, repo := range teamRepos {
 		permission, err := access_model.GetUserRepoPermission(ctx, repo, ctx.Doer)
 		if err != nil {
-			ctx.Error(http.StatusInternalServerError, "GetTeamRepos", err)
+			ctx.Error(http.StatusInternalServerError, "GetUserRepoPermission", err)
 			return
 		}
 		repos[i] = convert.ToRepo(ctx, repo, permission)
diff --git a/routers/api/v1/repo/teams.go b/routers/api/v1/repo/teams.go
index 82ecaf3020..42fb0a1d75 100644
--- a/routers/api/v1/repo/teams.go
+++ b/routers/api/v1/repo/teams.go
@@ -42,7 +42,7 @@ func ListTeams(ctx *context.APIContext) {
 		return
 	}
 
-	teams, err := organization.GetRepoTeams(ctx, ctx.Repo.Repository)
+	teams, err := organization.GetRepoTeams(ctx, ctx.Repo.Repository.OwnerID, ctx.Repo.Repository.ID)
 	if err != nil {
 		ctx.InternalServerError(err)
 		return
diff --git a/routers/api/v1/repo/transfer.go b/routers/api/v1/repo/transfer.go
index 776b336761..787ec34404 100644
--- a/routers/api/v1/repo/transfer.go
+++ b/routers/api/v1/repo/transfer.go
@@ -8,7 +8,6 @@ import (
 	"fmt"
 	"net/http"
 
-	"code.gitea.io/gitea/models"
 	"code.gitea.io/gitea/models/organization"
 	"code.gitea.io/gitea/models/perm"
 	access_model "code.gitea.io/gitea/models/perm/access"
@@ -108,7 +107,7 @@ func Transfer(ctx *context.APIContext) {
 	oldFullname := ctx.Repo.Repository.FullName()
 
 	if err := repo_service.StartRepositoryTransfer(ctx, ctx.Doer, newOwner, ctx.Repo.Repository, teams); err != nil {
-		if models.IsErrRepoTransferInProgress(err) {
+		if repo_model.IsErrRepoTransferInProgress(err) {
 			ctx.Error(http.StatusConflict, "StartRepositoryTransfer", err)
 			return
 		}
@@ -213,9 +212,9 @@ func RejectTransfer(ctx *context.APIContext) {
 }
 
 func acceptOrRejectRepoTransfer(ctx *context.APIContext, accept bool) error {
-	repoTransfer, err := models.GetPendingRepositoryTransfer(ctx, ctx.Repo.Repository)
+	repoTransfer, err := repo_model.GetPendingRepositoryTransfer(ctx, ctx.Repo.Repository)
 	if err != nil {
-		if models.IsErrNoPendingTransfer(err) {
+		if repo_model.IsErrNoPendingTransfer(err) {
 			ctx.NotFound()
 			return nil
 		}
diff --git a/routers/web/org/teams.go b/routers/web/org/teams.go
index bd78832103..b03b18bd9c 100644
--- a/routers/web/org/teams.go
+++ b/routers/web/org/teams.go
@@ -410,11 +410,15 @@ func TeamRepositories(ctx *context.Context) {
 		return
 	}
 
-	if err := ctx.Org.Team.LoadRepositories(ctx); err != nil {
-		ctx.ServerError("GetRepositories", err)
+	repos, err := repo_model.GetTeamRepositories(ctx, &repo_model.SearchTeamRepoOptions{
+		TeamID: ctx.Org.Team.ID,
+	})
+	if err != nil {
+		ctx.ServerError("GetTeamRepositories", err)
 		return
 	}
 	ctx.Data["Units"] = unit_model.Units
+	ctx.Data["TeamRepos"] = repos
 	ctx.HTML(http.StatusOK, tplTeamRepositories)
 }
 
diff --git a/routers/web/repo/repo.go b/routers/web/repo/repo.go
index f5e59b0357..4b017f61c4 100644
--- a/routers/web/repo/repo.go
+++ b/routers/web/repo/repo.go
@@ -11,7 +11,6 @@ import (
 	"slices"
 	"strings"
 
-	"code.gitea.io/gitea/models"
 	"code.gitea.io/gitea/models/db"
 	git_model "code.gitea.io/gitea/models/git"
 	"code.gitea.io/gitea/models/organization"
@@ -378,7 +377,7 @@ func Action(ctx *context.Context) {
 }
 
 func acceptOrRejectRepoTransfer(ctx *context.Context, accept bool) error {
-	repoTransfer, err := models.GetPendingRepositoryTransfer(ctx, ctx.Repo.Repository)
+	repoTransfer, err := repo_model.GetPendingRepositoryTransfer(ctx, ctx.Repo.Repository)
 	if err != nil {
 		return err
 	}
diff --git a/routers/web/repo/setting/collaboration.go b/routers/web/repo/setting/collaboration.go
index cdf91edf4a..df7cc5e39b 100644
--- a/routers/web/repo/setting/collaboration.go
+++ b/routers/web/repo/setting/collaboration.go
@@ -32,7 +32,7 @@ func Collaboration(ctx *context.Context) {
 	}
 	ctx.Data["Collaborators"] = users
 
-	teams, err := organization.GetRepoTeams(ctx, ctx.Repo.Repository)
+	teams, err := organization.GetRepoTeams(ctx, ctx.Repo.Repository.OwnerID, ctx.Repo.Repository.ID)
 	if err != nil {
 		ctx.ServerError("GetRepoTeams", err)
 		return
diff --git a/routers/web/repo/setting/setting.go b/routers/web/repo/setting/setting.go
index 717d7cbce1..f2169d8a79 100644
--- a/routers/web/repo/setting/setting.go
+++ b/routers/web/repo/setting/setting.go
@@ -788,7 +788,7 @@ func SettingsPost(ctx *context.Context) {
 		if err := repo_service.StartRepositoryTransfer(ctx, ctx.Doer, newOwner, repo, nil); err != nil {
 			if repo_model.IsErrRepoAlreadyExist(err) {
 				ctx.RenderWithErr(ctx.Tr("repo.settings.new_owner_has_same_repo"), tplSettingsOptions, nil)
-			} else if models.IsErrRepoTransferInProgress(err) {
+			} else if repo_model.IsErrRepoTransferInProgress(err) {
 				ctx.RenderWithErr(ctx.Tr("repo.settings.transfer_in_progress"), tplSettingsOptions, nil)
 			} else if errors.Is(err, user_model.ErrBlockedUser) {
 				ctx.RenderWithErr(ctx.Tr("repo.settings.transfer.blocked_user"), tplSettingsOptions, nil)
@@ -814,9 +814,9 @@ func SettingsPost(ctx *context.Context) {
 			return
 		}
 
-		repoTransfer, err := models.GetPendingRepositoryTransfer(ctx, ctx.Repo.Repository)
+		repoTransfer, err := repo_model.GetPendingRepositoryTransfer(ctx, ctx.Repo.Repository)
 		if err != nil {
-			if models.IsErrNoPendingTransfer(err) {
+			if repo_model.IsErrNoPendingTransfer(err) {
 				ctx.Flash.Error("repo.settings.transfer_abort_invalid")
 				ctx.Redirect(repo.Link() + "/settings")
 			} else {
diff --git a/services/context/repo.go b/services/context/repo.go
index 9b54439110..e96916ca42 100644
--- a/services/context/repo.go
+++ b/services/context/repo.go
@@ -14,7 +14,6 @@ import (
 	"path"
 	"strings"
 
-	"code.gitea.io/gitea/models"
 	"code.gitea.io/gitea/models/db"
 	git_model "code.gitea.io/gitea/models/git"
 	issues_model "code.gitea.io/gitea/models/issues"
@@ -709,7 +708,7 @@ func RepoAssignment(ctx *Context) context.CancelFunc {
 	ctx.Data["PullRequestCtx"] = ctx.Repo.PullRequest
 
 	if ctx.Repo.Repository.Status == repo_model.RepositoryPendingTransfer {
-		repoTransfer, err := models.GetPendingRepositoryTransfer(ctx, ctx.Repo.Repository)
+		repoTransfer, err := repo_model.GetPendingRepositoryTransfer(ctx, ctx.Repo.Repository)
 		if err != nil {
 			ctx.ServerError("GetPendingRepositoryTransfer", err)
 			return cancel
diff --git a/services/convert/repository.go b/services/convert/repository.go
index e026d0f440..88ccd88fcf 100644
--- a/services/convert/repository.go
+++ b/services/convert/repository.go
@@ -7,7 +7,6 @@ import (
 	"context"
 	"time"
 
-	"code.gitea.io/gitea/models"
 	"code.gitea.io/gitea/models/db"
 	"code.gitea.io/gitea/models/perm"
 	access_model "code.gitea.io/gitea/models/perm/access"
@@ -158,8 +157,8 @@ func innerToRepo(ctx context.Context, repo *repo_model.Repository, permissionInR
 
 	var transfer *api.RepoTransfer
 	if repo.Status == repo_model.RepositoryPendingTransfer {
-		t, err := models.GetPendingRepositoryTransfer(ctx, repo)
-		if err != nil && !models.IsErrNoPendingTransfer(err) {
+		t, err := repo_model.GetPendingRepositoryTransfer(ctx, repo)
+		if err != nil && !repo_model.IsErrNoPendingTransfer(err) {
 			log.Warn("GetPendingRepositoryTransfer: %v", err)
 		} else {
 			if err := t.LoadAttributes(ctx); err != nil {
@@ -248,7 +247,7 @@ func innerToRepo(ctx context.Context, repo *repo_model.Repository, permissionInR
 }
 
 // ToRepoTransfer convert a models.RepoTransfer to a structs.RepeTransfer
-func ToRepoTransfer(ctx context.Context, t *models.RepoTransfer) *api.RepoTransfer {
+func ToRepoTransfer(ctx context.Context, t *repo_model.RepoTransfer) *api.RepoTransfer {
 	teams, _ := ToTeams(ctx, t.Teams, false)
 
 	return &api.RepoTransfer{
diff --git a/services/org/org.go b/services/org/org.go
index c19572a123..471e6fcaf1 100644
--- a/services/org/org.go
+++ b/services/org/org.go
@@ -8,16 +8,45 @@ import (
 	"fmt"
 
 	"code.gitea.io/gitea/models"
+	actions_model "code.gitea.io/gitea/models/actions"
 	"code.gitea.io/gitea/models/db"
 	org_model "code.gitea.io/gitea/models/organization"
 	packages_model "code.gitea.io/gitea/models/packages"
 	repo_model "code.gitea.io/gitea/models/repo"
+	secret_model "code.gitea.io/gitea/models/secret"
 	user_model "code.gitea.io/gitea/models/user"
 	"code.gitea.io/gitea/modules/storage"
 	"code.gitea.io/gitea/modules/util"
 	repo_service "code.gitea.io/gitea/services/repository"
 )
 
+// deleteOrganization deletes models associated to an organization.
+func deleteOrganization(ctx context.Context, org *org_model.Organization) error {
+	if org.Type != user_model.UserTypeOrganization {
+		return fmt.Errorf("%s is a user not an organization", org.Name)
+	}
+
+	if err := db.DeleteBeans(ctx,
+		&org_model.Team{OrgID: org.ID},
+		&org_model.OrgUser{OrgID: org.ID},
+		&org_model.TeamUser{OrgID: org.ID},
+		&org_model.TeamUnit{OrgID: org.ID},
+		&org_model.TeamInvite{OrgID: org.ID},
+		&secret_model.Secret{OwnerID: org.ID},
+		&user_model.Blocking{BlockerID: org.ID},
+		&actions_model.ActionRunner{OwnerID: org.ID},
+		&actions_model.ActionRunnerToken{OwnerID: org.ID},
+	); err != nil {
+		return fmt.Errorf("DeleteBeans: %w", err)
+	}
+
+	if _, err := db.GetEngine(ctx).ID(org.ID).Delete(new(user_model.User)); err != nil {
+		return fmt.Errorf("Delete: %w", err)
+	}
+
+	return nil
+}
+
 // DeleteOrganization completely and permanently deletes everything of organization.
 func DeleteOrganization(ctx context.Context, org *org_model.Organization, purge bool) error {
 	ctx, committer, err := db.TxContext(ctx)
@@ -48,7 +77,7 @@ func DeleteOrganization(ctx context.Context, org *org_model.Organization, purge
 		return models.ErrUserOwnPackages{UID: org.ID}
 	}
 
-	if err := org_model.DeleteOrganization(ctx, org); err != nil {
+	if err := deleteOrganization(ctx, org); err != nil {
 		return fmt.Errorf("DeleteOrganization: %w", err)
 	}
 
diff --git a/services/org/team.go b/services/org/team.go
index 3688e68433..ee3bd898ea 100644
--- a/services/org/team.go
+++ b/services/org/team.go
@@ -141,11 +141,14 @@ func UpdateTeam(ctx context.Context, t *organization.Team, authChanged, includeA
 
 	// Update access for team members if needed.
 	if authChanged {
-		if err = t.LoadRepositories(ctx); err != nil {
-			return fmt.Errorf("LoadRepositories: %w", err)
+		repos, err := repo_model.GetTeamRepositories(ctx, &repo_model.SearchTeamRepoOptions{
+			TeamID: t.ID,
+		})
+		if err != nil {
+			return fmt.Errorf("GetTeamRepositories: %w", err)
 		}
 
-		for _, repo := range t.Repos {
+		for _, repo := range repos {
 			if err = access_model.RecalculateTeamAccesses(ctx, repo, 0); err != nil {
 				return fmt.Errorf("recalculateTeamAccesses: %w", err)
 			}
@@ -172,10 +175,6 @@ func DeleteTeam(ctx context.Context, t *organization.Team) error {
 	}
 	defer committer.Close()
 
-	if err := t.LoadRepositories(ctx); err != nil {
-		return err
-	}
-
 	if err := t.LoadMembers(ctx); err != nil {
 		return err
 	}
@@ -301,8 +300,11 @@ func AddTeamMember(ctx context.Context, team *organization.Team, user *user_mode
 	// FIXME: Update watch repos batchly
 	if setting.Service.AutoWatchNewRepos {
 		// Get team and its repositories.
-		if err := team.LoadRepositories(ctx); err != nil {
-			log.Error("team.LoadRepositories failed: %v", err)
+		repos, err := repo_model.GetTeamRepositories(ctx, &repo_model.SearchTeamRepoOptions{
+			TeamID: team.ID,
+		})
+		if err != nil {
+			log.Error("GetTeamRepositories failed: %v", err)
 		}
 
 		// FIXME: in the goroutine, it can't access the "ctx", it could only use db.DefaultContext at the moment
@@ -312,7 +314,7 @@ func AddTeamMember(ctx context.Context, team *organization.Team, user *user_mode
 					log.Error("watch repo failed: %v", err)
 				}
 			}
-		}(team.Repos)
+		}(repos)
 	}
 
 	return nil
@@ -332,7 +334,10 @@ func removeTeamMember(ctx context.Context, team *organization.Team, user *user_m
 
 	team.NumMembers--
 
-	if err := team.LoadRepositories(ctx); err != nil {
+	repos, err := repo_model.GetTeamRepositories(ctx, &repo_model.SearchTeamRepoOptions{
+		TeamID: team.ID,
+	})
+	if err != nil {
 		return err
 	}
 
@@ -350,7 +355,7 @@ func removeTeamMember(ctx context.Context, team *organization.Team, user *user_m
 	}
 
 	// Delete access to team repositories.
-	for _, repo := range team.Repos {
+	for _, repo := range repos {
 		if err := access_model.RecalculateUserAccess(ctx, repo, user.ID); err != nil {
 			return err
 		}
diff --git a/services/org/team_test.go b/services/org/team_test.go
index 98addac8f8..3791776e46 100644
--- a/services/org/team_test.go
+++ b/services/org/team_test.go
@@ -189,9 +189,12 @@ func TestIncludesAllRepositoriesTeams(t *testing.T) {
 
 	testTeamRepositories := func(teamID int64, repoIDs []int64) {
 		team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID})
-		assert.NoError(t, team.LoadRepositories(db.DefaultContext), "%s: GetRepositories", team.Name)
-		assert.Len(t, team.Repos, team.NumRepos, "%s: len repo", team.Name)
-		assert.Len(t, team.Repos, len(repoIDs), "%s: repo count", team.Name)
+		repos, err := repo_model.GetTeamRepositories(db.DefaultContext, &repo_model.SearchTeamRepoOptions{
+			TeamID: team.ID,
+		})
+		assert.NoError(t, err, "%s: GetTeamRepositories", team.Name)
+		assert.Len(t, repos, team.NumRepos, "%s: len repo", team.Name)
+		assert.Len(t, repos, len(repoIDs), "%s: repo count", team.Name)
 		for i, rid := range repoIDs {
 			if rid > 0 {
 				assert.True(t, repo_service.HasRepository(db.DefaultContext, team, rid), "%s: HasRepository(%d) %d", rid, i)
@@ -310,5 +313,5 @@ func TestIncludesAllRepositoriesTeams(t *testing.T) {
 			assert.NoError(t, repo_service.DeleteRepositoryDirectly(db.DefaultContext, user, rid), "DeleteRepository %d", i)
 		}
 	}
-	assert.NoError(t, organization.DeleteOrganization(db.DefaultContext, org), "DeleteOrganization")
+	assert.NoError(t, DeleteOrganization(db.DefaultContext, org, false), "DeleteOrganization")
 }
diff --git a/services/org/user.go b/services/org/user.go
index 0627860fe7..0e74d006bb 100644
--- a/services/org/user.go
+++ b/services/org/user.go
@@ -60,7 +60,7 @@ func RemoveOrgUser(ctx context.Context, org *organization.Organization, user *us
 	}
 
 	// Delete all repository accesses and unwatch them.
-	env, err := organization.AccessibleReposEnv(ctx, org, user.ID)
+	env, err := repo_model.AccessibleReposEnv(ctx, org, user.ID)
 	if err != nil {
 		return fmt.Errorf("AccessibleReposEnv: %w", err)
 	}
diff --git a/services/repository/repo_team.go b/services/repository/repo_team.go
index 29c67893b2..672ee49fea 100644
--- a/services/repository/repo_team.go
+++ b/services/repository/repo_team.go
@@ -63,7 +63,7 @@ func addRepositoryToTeam(ctx context.Context, t *organization.Team, repo *repo_m
 // If the team already has some repositories they will be left unchanged.
 func AddAllRepositoriesToTeam(ctx context.Context, t *organization.Team) error {
 	return db.WithTx(ctx, func(ctx context.Context) error {
-		orgRepos, err := organization.GetOrgRepositories(ctx, t.OrgID)
+		orgRepos, err := repo_model.GetOrgRepositories(ctx, t.OrgID)
 		if err != nil {
 			return fmt.Errorf("get org repos: %w", err)
 		}
@@ -103,8 +103,15 @@ func RemoveAllRepositoriesFromTeam(ctx context.Context, t *organization.Team) (e
 // Note: Shall not be called if team includes all repositories
 func removeAllRepositoriesFromTeam(ctx context.Context, t *organization.Team) (err error) {
 	e := db.GetEngine(ctx)
+	repos, err := repo_model.GetTeamRepositories(ctx, &repo_model.SearchTeamRepoOptions{
+		TeamID: t.ID,
+	})
+	if err != nil {
+		return fmt.Errorf("GetTeamRepositories: %w", err)
+	}
+
 	// Delete all accesses.
-	for _, repo := range t.Repos {
+	for _, repo := range repos {
 		if err := access_model.RecalculateTeamAccesses(ctx, repo, t.ID); err != nil {
 			return err
 		}
diff --git a/services/repository/transfer.go b/services/repository/transfer.go
index 9a643469d9..9ef28ddeb9 100644
--- a/services/repository/transfer.go
+++ b/services/repository/transfer.go
@@ -9,7 +9,6 @@ import (
 	"os"
 	"strings"
 
-	"code.gitea.io/gitea/models"
 	"code.gitea.io/gitea/models/db"
 	issues_model "code.gitea.io/gitea/models/issues"
 	"code.gitea.io/gitea/models/organization"
@@ -285,7 +284,7 @@ func transferOwnership(ctx context.Context, doer *user_model.User, newOwnerName
 		wikiRenamed = true
 	}
 
-	if err := models.DeleteRepositoryTransfer(ctx, repo.ID); err != nil {
+	if err := repo_model.DeleteRepositoryTransfer(ctx, repo.ID); err != nil {
 		return fmt.Errorf("deleteRepositoryTransfer: %w", err)
 	}
 	repo.Status = repo_model.RepositoryReady
@@ -388,7 +387,7 @@ func ChangeRepositoryName(ctx context.Context, doer *user_model.User, repo *repo
 // StartRepositoryTransfer transfer a repo from one owner to a new one.
 // it make repository into pending transfer state, if doer can not create repo for new owner.
 func StartRepositoryTransfer(ctx context.Context, doer, newOwner *user_model.User, repo *repo_model.Repository, teams []*organization.Team) error {
-	if err := models.TestRepositoryReadyForTransfer(repo.Status); err != nil {
+	if err := repo_model.TestRepositoryReadyForTransfer(repo.Status); err != nil {
 		return err
 	}
 
@@ -425,7 +424,7 @@ func StartRepositoryTransfer(ctx context.Context, doer, newOwner *user_model.Use
 
 	// Make repo as pending for transfer
 	repo.Status = repo_model.RepositoryPendingTransfer
-	if err := models.CreatePendingRepositoryTransfer(ctx, doer, newOwner, repo.ID, teams); err != nil {
+	if err := repo_model.CreatePendingRepositoryTransfer(ctx, doer, newOwner, repo.ID, teams); err != nil {
 		return err
 	}
 
@@ -449,7 +448,7 @@ func CancelRepositoryTransfer(ctx context.Context, repo *repo_model.Repository)
 		return err
 	}
 
-	if err := models.DeleteRepositoryTransfer(ctx, repo.ID); err != nil {
+	if err := repo_model.DeleteRepositoryTransfer(ctx, repo.ID); err != nil {
 		return err
 	}
 
diff --git a/services/repository/transfer_test.go b/services/repository/transfer_test.go
index 0401701ba5..91722fb8ae 100644
--- a/services/repository/transfer_test.go
+++ b/services/repository/transfer_test.go
@@ -7,7 +7,6 @@ import (
 	"sync"
 	"testing"
 
-	"code.gitea.io/gitea/models"
 	activities_model "code.gitea.io/gitea/models/activities"
 	"code.gitea.io/gitea/models/db"
 	"code.gitea.io/gitea/models/organization"
@@ -86,23 +85,23 @@ func TestRepositoryTransfer(t *testing.T) {
 	doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3})
 	repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3})
 
-	transfer, err := models.GetPendingRepositoryTransfer(db.DefaultContext, repo)
+	transfer, err := repo_model.GetPendingRepositoryTransfer(db.DefaultContext, repo)
 	assert.NoError(t, err)
 	assert.NotNil(t, transfer)
 
 	// Cancel transfer
 	assert.NoError(t, CancelRepositoryTransfer(db.DefaultContext, repo))
 
-	transfer, err = models.GetPendingRepositoryTransfer(db.DefaultContext, repo)
+	transfer, err = repo_model.GetPendingRepositoryTransfer(db.DefaultContext, repo)
 	assert.Error(t, err)
 	assert.Nil(t, transfer)
-	assert.True(t, models.IsErrNoPendingTransfer(err))
+	assert.True(t, repo_model.IsErrNoPendingTransfer(err))
 
 	user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
 
-	assert.NoError(t, models.CreatePendingRepositoryTransfer(db.DefaultContext, doer, user2, repo.ID, nil))
+	assert.NoError(t, repo_model.CreatePendingRepositoryTransfer(db.DefaultContext, doer, user2, repo.ID, nil))
 
-	transfer, err = models.GetPendingRepositoryTransfer(db.DefaultContext, repo)
+	transfer, err = repo_model.GetPendingRepositoryTransfer(db.DefaultContext, repo)
 	assert.NoError(t, err)
 	assert.NoError(t, transfer.LoadAttributes(db.DefaultContext))
 	assert.Equal(t, "user2", transfer.Recipient.Name)
@@ -110,12 +109,12 @@ func TestRepositoryTransfer(t *testing.T) {
 	org6 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
 
 	// Only transfer can be started at any given time
-	err = models.CreatePendingRepositoryTransfer(db.DefaultContext, doer, org6, repo.ID, nil)
+	err = repo_model.CreatePendingRepositoryTransfer(db.DefaultContext, doer, org6, repo.ID, nil)
 	assert.Error(t, err)
-	assert.True(t, models.IsErrRepoTransferInProgress(err))
+	assert.True(t, repo_model.IsErrRepoTransferInProgress(err))
 
 	// Unknown user
-	err = models.CreatePendingRepositoryTransfer(db.DefaultContext, doer, &user_model.User{ID: 1000, LowerName: "user1000"}, repo.ID, nil)
+	err = repo_model.CreatePendingRepositoryTransfer(db.DefaultContext, doer, &user_model.User{ID: 1000, LowerName: "user1000"}, repo.ID, nil)
 	assert.Error(t, err)
 
 	// Cancel transfer
diff --git a/services/user/block.go b/services/user/block.go
index 0b3b618aae..c24ce5273c 100644
--- a/services/user/block.go
+++ b/services/user/block.go
@@ -6,7 +6,6 @@ package user
 import (
 	"context"
 
-	"code.gitea.io/gitea/models"
 	"code.gitea.io/gitea/models/db"
 	issues_model "code.gitea.io/gitea/models/issues"
 	org_model "code.gitea.io/gitea/models/organization"
@@ -194,7 +193,7 @@ func unwatchRepos(ctx context.Context, watcher, repoOwner *user_model.User) erro
 }
 
 func cancelRepositoryTransfers(ctx context.Context, sender, recipient *user_model.User) error {
-	transfers, err := models.GetPendingRepositoryTransfers(ctx, &models.PendingRepositoryTransferOptions{
+	transfers, err := repo_model.GetPendingRepositoryTransfers(ctx, &repo_model.PendingRepositoryTransferOptions{
 		SenderID:    sender.ID,
 		RecipientID: recipient.ID,
 	})
diff --git a/templates/org/team/repositories.tmpl b/templates/org/team/repositories.tmpl
index 502cf97992..92c3d724ba 100644
--- a/templates/org/team/repositories.tmpl
+++ b/templates/org/team/repositories.tmpl
@@ -27,7 +27,7 @@
 				{{end}}
 				<div class="ui{{if not $canAddRemove}} top{{end}} attached segment">
 					<div class="flex-list">
-						{{range .Team.Repos}}
+						{{range $.TeamRepos}}
 							<div class="flex-item tw-items-center">
 								<div class="flex-item-leading">
 									{{template "repo/icon" .}}
diff --git a/tests/integration/api_user_block_test.go b/tests/integration/api_user_block_test.go
index 2cc3895a71..ae6b9eb849 100644
--- a/tests/integration/api_user_block_test.go
+++ b/tests/integration/api_user_block_test.go
@@ -8,7 +8,6 @@ import (
 	"net/http"
 	"testing"
 
-	"code.gitea.io/gitea/models"
 	auth_model "code.gitea.io/gitea/models/auth"
 	"code.gitea.io/gitea/models/db"
 	issues_model "code.gitea.io/gitea/models/issues"
@@ -42,7 +41,7 @@ func TestBlockUser(t *testing.T) {
 	}
 
 	countRepositoryTransfers := func(t *testing.T, senderID, recipientID int64) int64 {
-		transfers, err := models.GetPendingRepositoryTransfers(db.DefaultContext, &models.PendingRepositoryTransferOptions{
+		transfers, err := repo_model.GetPendingRepositoryTransfers(db.DefaultContext, &repo_model.PendingRepositoryTransferOptions{
 			SenderID:    senderID,
 			RecipientID: recipientID,
 		})