feat(group-quota): per-group shared-collection quotas (M3)
Global env-var ceilings enforced in the group write path (mirrors the per-value caps): PICLOUD_GROUP_KV_MAX_ROWS / _DOCS_MAX_ROWS (per-group row count, checked only on a NEW key/doc — updates exempt) and _FILES_MAX_TOTAL_BYTES (per-group total blob bytes). New group_quota env helpers; count_rows/total_bytes repo methods (trait-default 0 for non-Postgres); QuotaExceeded error variants on the three group error enums; a with_max_rows test builder. Pinned by a group_kv_service unit test (3rd key rejected, update of an existing key at the cap allowed). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -114,6 +114,13 @@ pub trait GroupFilesRepo: Send + Sync {
|
||||
cursor: Option<&str>,
|
||||
limit: u32,
|
||||
) -> Result<FilesListPage, GroupFilesRepoError>;
|
||||
|
||||
/// §11.6 quota: total stored bytes across the group's shared-files
|
||||
/// collections. Default `Ok(0)` so non-Postgres impls skip the check.
|
||||
async fn total_bytes(&self, group_id: GroupId) -> Result<u64, GroupFilesRepoError> {
|
||||
let _ = group_id;
|
||||
Ok(0)
|
||||
}
|
||||
}
|
||||
|
||||
/// Filesystem-bytes + Postgres-metadata repo for group-shared files.
|
||||
@@ -369,6 +376,16 @@ impl GroupFilesRepo for FsGroupFilesRepo {
|
||||
};
|
||||
Ok(FilesListPage { files, next_cursor })
|
||||
}
|
||||
|
||||
async fn total_bytes(&self, group_id: GroupId) -> Result<u64, GroupFilesRepoError> {
|
||||
let (n,): (i64,) = sqlx::query_as(
|
||||
"SELECT COALESCE(SUM(size_bytes), 0)::bigint FROM group_files WHERE group_id = $1",
|
||||
)
|
||||
.bind(group_id.into_inner())
|
||||
.fetch_one(&self.pool)
|
||||
.await?;
|
||||
Ok(u64::try_from(n).unwrap_or(0))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(sqlx::FromRow)]
|
||||
|
||||
Reference in New Issue
Block a user