feat: add paginated project discovery

This commit is contained in:
2026-07-12 01:45:15 +08:00
parent 53d372e29b
commit 816af1abdb
14 changed files with 1505 additions and 237 deletions
+30
View File
@@ -46,6 +46,7 @@ model Organization {
agentSkills OrganizationAgentSkill[]
agentRoles OrganizationAgentRole[]
auditEntries AuditEntry[] @relation("organizationAudit")
projectSearchDocuments ProjectSearchDocument[]
@@index([status])
}
@@ -437,11 +438,17 @@ model ExternalPrincipalMembership {
/// ADR-0021: transparent project explorer folder. Folders are org-scoped
/// navigation/aggregation nodes, not permission resources; project grants stay
/// attached to PROJECT resources.
enum FolderKind {
REGULAR
SYSTEM_INBOX
}
model Folder {
id String @id @default(cuid())
organizationId String
parentId String?
name String
kind FolderKind @default(REGULAR)
sortKey String @default("")
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@ -460,6 +467,7 @@ model Project {
id String @id @default(cuid())
organizationId String
folderId String?
code String?
name String
workspaceDir String
createdByUserId String?
@@ -477,12 +485,34 @@ model Project {
roleTriggerGrants RoleTriggerGrant[] @relation("projectRoleGrants")
auditEntries AuditEntry[] @relation("projectAudit")
fileChanges AgentFileChange[] @relation("projectFileChanges")
searchDocument ProjectSearchDocument?
@@index([organizationId, archivedAt])
@@index([folderId, archivedAt])
@@index([archivedAt])
}
/// Derived, rebuildable search projection for project discovery. PostgreSQL
/// triggers keep it synchronized with Project and Folder mutations; Project
/// remains the source of truth and authorization remains outside this table.
model ProjectSearchDocument {
projectId String @id
organizationId String
name String
code String?
normalizedCode String
normalizedName String
breadcrumb String
normalizedBreadcrumb String
normalizedSearchText String
updatedAt DateTime @updatedAt
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
@@index([organizationId])
}
/// ADR-0001 + ADR-0021: active bindings are one project ↔ one Feishu chat
/// (1:1). Historical archived bindings are retained for audit; partial unique
/// indexes in migrations enforce one active binding per project and per chat.