feat(projects): projects repo + group owner reads; wire into ApplyService

Read side of §7 ownership, ahead of the claim logic.

- project_repo: `ProjectRepository` trait + `PostgresProjectRepository`
  (list / get_by_id / get_by_slug). Writes are NOT here — a claim registers
  its project via an in-tx upsert (next commit).
- group_repo: `list_with_owner()` LEFT-JOINs projects for each group's owner
  slug (backs `pic groups ls`); columns qualified since id/slug/name exist on
  both tables.
- ApplyService gains a `projects` handle; constructed in the picloud binary.
- tests/projects_repo: round-trip pinning list_with_owner (claimed→slug,
  unclaimed→None) and that ancestors() surfaces owner_project nearest-first —
  the fold input the claim path walks.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
MechaCat02
2026-07-06 20:13:34 +02:00
parent ba97c35aaf
commit 2cce051dc4
6 changed files with 243 additions and 6 deletions

View File

@@ -31,12 +31,13 @@ use picloud_manager_core::{
PostgresDocsRepo, PostgresExecutionLogRepository, PostgresExecutionLogSink,
PostgresGroupCollectionResolver, PostgresGroupDocsRepo, PostgresGroupKvRepo,
PostgresGroupMembersRepository, PostgresGroupQueueRepo, PostgresGroupRepository,
PostgresKvRepo, PostgresOutboxRepo, PostgresPubsubRepo, PostgresRouteRepository,
PostgresScriptRepository, PostgresSecretsRepo, PostgresTopicRepo, PostgresTriggerRepo,
PostgresVarsRepo, PrincipalResolver, PubsubServiceImpl, RealtimeAuthorityImpl, RepoResolver,
RouteAdminState, SandboxCeiling, ScriptRepository, SecretsConfig, SecretsServiceImpl,
SecretsState, SubscriberTokenConfig, TopicRepo, TopicsState, TriggerConfig, TriggerRepo,
TriggersState, UsersServiceConfig, UsersServiceImpl, VarsApiState, VarsServiceImpl,
PostgresKvRepo, PostgresOutboxRepo, PostgresProjectRepository, PostgresPubsubRepo,
PostgresRouteRepository, PostgresScriptRepository, PostgresSecretsRepo, PostgresTopicRepo,
PostgresTriggerRepo, PostgresVarsRepo, PrincipalResolver, PubsubServiceImpl,
RealtimeAuthorityImpl, RepoResolver, RouteAdminState, SandboxCeiling, ScriptRepository,
SecretsConfig, SecretsServiceImpl, SecretsState, SubscriberTokenConfig, TopicRepo, TopicsState,
TriggerConfig, TriggerRepo, TriggersState, UsersServiceConfig, UsersServiceImpl, VarsApiState,
VarsServiceImpl,
};
use picloud_orchestrator_core::realtime::DEFAULT_GC_INTERVAL_SECS;
use picloud_orchestrator_core::routing::{AppDomainTable, RouteTable};
@@ -537,6 +538,7 @@ pub async fn build_app(
vars: Arc::new(PostgresVarsRepo::new(pool.clone())),
apps: apps_repo.clone(),
groups: groups_repo.clone(),
projects: Arc::new(PostgresProjectRepository::new(pool.clone())),
modules: modules.clone(),
domains: domains_repo.clone(),
authz: authz.clone(),