feat(cli): per-app docs admin read (pic docs ls/get --app)

Fills the one per-app admin-read gap kv/files already covered. New
docs_api.rs mirrors kv_api (GET /apps/{id}/docs[/{collection}/{doc_id}],
AppDocsRead capability, DocsRepo::list/get) with the group_blobs_api docs
response shape so the CLI shares one deserialize. DocsCmd gains optional
--app/--group (mutually exclusive, like KvCmd) dispatched via
require_one_owner; new client docs_list/docs_get. Read-only by design,
matching kv/files. Pinned by a collections journey: a script writes the
app's own docs collection, the operator lists + fetches it with no script.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
MechaCat02
2026-07-15 20:53:11 +02:00
parent 8fc78cd07f
commit e4a58dc140
7 changed files with 366 additions and 38 deletions

View File

@@ -12,32 +12,33 @@ use picloud_executor_core::{Engine, Limits};
use picloud_manager_core::{
admin_router, admins_router, api_keys_router, app_members_router, apply_router, apps_api,
apps_router, attach_principal_if_present, auth_router, dead_letters_router, dev_emails_router,
email_inbound_router, files_admin_router, groups_router, kv_admin_router, migrations,
projects_router, rebuild_route_table, require_authenticated, route_admin_router,
docs_admin_router, email_inbound_router, files_admin_router, groups_router, kv_admin_router,
migrations, projects_router, rebuild_route_table, require_authenticated, route_admin_router,
secrets_router, topics_router, triggers_router, vars_router, AbandonedRepo,
AdminPrincipalResolver, AdminSessionRepository, AdminState, AdminUserRepository, AdminsState,
ApiKeyRepository, ApiKeysState, AppDomainRepository, AppMembersRepository, AppMembersState,
AppRepository, ApplyService, AppsState, AuthState, AuthzRepo, DeadLetterRepo, DeadLettersState,
DevEmailState, Dispatcher, DocsServiceImpl, EmailInboundState, EmailServiceImpl,
FilesAdminState, FilesConfig, FilesServiceImpl, FsFilesRepo, FsGroupFilesRepo,
GroupDocsServiceImpl, GroupFilesServiceImpl, GroupKvServiceImpl, GroupMembersRepository,
GroupPubsubServiceImpl, GroupQueueServiceImpl, GroupRepository, GroupsState, HttpConfig,
HttpServiceImpl, InboundNonceDedup, KvAdminState, KvServiceImpl, OutboxEventEmitter,
OutboxRepo, PostgresAbandonedRepo, PostgresAdminSessionRepository, PostgresAdminUserRepository,
PostgresApiKeyRepository, PostgresAppDomainRepository, PostgresAppMembersRepository,
PostgresAppRepository, PostgresAppSecretsRepo, PostgresAppUserInvitationRepo,
PostgresAppUserPasswordResetRepo, PostgresAppUserRepository, PostgresAppUserRoleRepo,
PostgresAppUserSessionRepository, PostgresAppUserVerificationRepo, PostgresDeadLetterRepo,
PostgresDeadLetterService, PostgresDocsRepo, PostgresExecutionLogRepository,
PostgresExecutionLogSink, PostgresGroupCollectionResolver, PostgresGroupDocsRepo,
PostgresGroupKvRepo, PostgresGroupMembersRepository, PostgresGroupQueueRepo,
PostgresGroupRepository, PostgresKvRepo, PostgresOutboxRepo, PostgresProjectRepository,
PostgresPubsubRepo, PostgresRouteRepository, PostgresScriptRepository, PostgresSecretsRepo,
PostgresTopicRepo, PostgresTriggerRepo, PostgresVarsRepo, PrincipalResolver, ProjectRepository,
ProjectsState, PubsubServiceImpl, RealtimeAuthorityImpl, RepoResolver, RouteAdminState,
SandboxCeiling, ScriptRepository, SecretsConfig, SecretsServiceImpl, SecretsState,
SubscriberTokenConfig, TopicRepo, TopicsState, TriggerConfig, TriggerRepo, TriggersState,
UsersServiceConfig, UsersServiceImpl, VarsApiState, VarsServiceImpl,
DevEmailState, Dispatcher, DocsAdminState, DocsServiceImpl, EmailInboundState,
EmailServiceImpl, FilesAdminState, FilesConfig, FilesServiceImpl, FsFilesRepo,
FsGroupFilesRepo, GroupDocsServiceImpl, GroupFilesServiceImpl, GroupKvServiceImpl,
GroupMembersRepository, GroupPubsubServiceImpl, GroupQueueServiceImpl, GroupRepository,
GroupsState, HttpConfig, HttpServiceImpl, InboundNonceDedup, KvAdminState, KvServiceImpl,
OutboxEventEmitter, OutboxRepo, PostgresAbandonedRepo, PostgresAdminSessionRepository,
PostgresAdminUserRepository, PostgresApiKeyRepository, PostgresAppDomainRepository,
PostgresAppMembersRepository, PostgresAppRepository, PostgresAppSecretsRepo,
PostgresAppUserInvitationRepo, PostgresAppUserPasswordResetRepo, PostgresAppUserRepository,
PostgresAppUserRoleRepo, PostgresAppUserSessionRepository, PostgresAppUserVerificationRepo,
PostgresDeadLetterRepo, PostgresDeadLetterService, PostgresDocsRepo,
PostgresExecutionLogRepository, PostgresExecutionLogSink, PostgresGroupCollectionResolver,
PostgresGroupDocsRepo, PostgresGroupKvRepo, PostgresGroupMembersRepository,
PostgresGroupQueueRepo, PostgresGroupRepository, PostgresKvRepo, PostgresOutboxRepo,
PostgresProjectRepository, PostgresPubsubRepo, PostgresRouteRepository,
PostgresScriptRepository, PostgresSecretsRepo, PostgresTopicRepo, PostgresTriggerRepo,
PostgresVarsRepo, PrincipalResolver, ProjectRepository, ProjectsState, 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};
@@ -217,7 +218,7 @@ pub async fn build_app(
);
let docs: Arc<dyn DocsService> = Arc::new(
DocsServiceImpl::with_max_value_bytes(
docs_repo,
docs_repo.clone(),
authz.clone(),
events.clone(),
picloud_manager_core::docs_service::docs_max_value_bytes_from_env(),
@@ -804,6 +805,11 @@ pub async fn build_app(
apps: apps_repo.clone(),
authz: authz.clone(),
}))
.merge(docs_admin_router(DocsAdminState {
docs: docs_repo.clone(),
apps: apps_repo.clone(),
authz: authz.clone(),
}))
// §11.6 M4: read-only operator inspection of a group's shared collections.
.merge(picloud_manager_core::group_blobs_api::group_blobs_router(
picloud_manager_core::group_blobs_api::GroupBlobsState {