type Query { # Returns REQUIRE_SETUP if config is missing. systemStatus: SystemStatus! # Fetch current configuration (admin only). config: AppConfig! # List directories on the server for UI pickers. serverDirectories(path: String): [ServerDirectory!]! # Fetch a document by its slug path. document(slug: String!): Document # List documents under an optional path prefix. documents(prefix: String): [DocumentMeta!]! # List all relative folder paths in the repository. folders: [String!]! # Commit history for a document. history(slug: String!): [CommitEntry!]! # Unified diff between two commits for a document. diff(slug: String!, fromHash: String!, toHash: String!): String! # Raw content of a document at a specific commit. documentAtCommit(slug: String!, hash: String!): String! # Whether the current storage path has uncommitted files. repoStatus: RepoStatus! # List images next to a document. images(slug: String!): [ImageFile!]! # Browse LDAP tree (admin only) ldapBrowse(url: String, baseDN: String, adminUser: String, adminPass: String): LDAPTree! # Fetch permissions for a path acl(path: String!): [ACLEntry!]! # Fetch all permissions for a specific user or group (admin only). subjectAcl(subjectType: String!, subjectId: Int!): [ACLEntry!]! # Returns all users and groups that can be assigned to ACL entries (admin only). aclSubjects: ACLSubjects! # Returns "local", "ldap", or "guest" for a given username. userAuthType(username: String!): String! # Returns the role of the currently authenticated user ("admin", "user", "guest"). currentUserRole: String! # Sign-in methods the login page should offer (public, no auth required). loginOptions: LoginOptions! # All local/external users with role & login state (admin only). users: [UserInfo!]! # Current OpenID Connect (Authentik) configuration (admin only, no secret). oidcConfig: OIDCConfigView! # Names of the groups a user belongs to (admin only). userGroups(username: String!): [String!]! # Effective permissions the current user has on each path (for UI gating). myAccess(paths: [String!]!): [PathAccess!]! # Effective permissions a subject has on each path (admin only, for the # access-control tree). For a user this includes their group memberships. subjectAccess(subjectType: String!, subjectId: Int!, paths: [String!]!): [PathAccess!]! # Git sync settings incl. the public deploy key (admin only). gitSyncSettings: GitSyncSettings! # Live git sync state: branch, ahead/behind, conflicts (admin only). gitSyncStatus: GitSyncStatus! # Local and remote branches (admin only). gitBranches: GitBranches! } type PathAccess { path: String! canSearch: Boolean! canView: Boolean! canRead: Boolean! canEdit: Boolean! canCreate: Boolean! canDelete: Boolean! canMove: Boolean! } type Mutation { # First-run setup. setup(input: SetupInput!): Boolean! # Test an LDAP configuration. testLdapConnection(url: String!, adminUser: String, adminPass: String): LDAPTestResult! # Authenticate and receive a bearer token. login(username: String!, password: String!, ldapPassword: String): String! # Invalidate the current session. logout: Boolean! # Save (create or update) a document. saveDocument(input: SaveDocumentInput!): Document! # Delete a document. deleteDocument(slug: String!): Boolean! # Modify LDAP Configuration (admin only). updateLdapConfig(input: LDAPInput): Boolean! # Modify OpenID Connect (Authentik) configuration (admin only). updateOidcConfig(input: OIDCInput!): Boolean! # Sync users/groups from LDAP importLdapSubject(type: String!, name: String!): Boolean! # Group management (admin only). createGroup(name: String!): Boolean! deleteGroup(name: String!): Boolean! addUserToGroup(username: String!, group: String!): Boolean! removeUserFromGroup(username: String!, group: String!): Boolean! # Who may sign in (admin only). setUserLogin(username: String!, allow: Boolean!): Boolean! setGroupLogin(name: String!, allow: Boolean!): Boolean! # Change a user's application role: "admin" | "user" (admin only). setUserRole(username: String!, role: String!): Boolean! # ACL Mutations setAcl(input: ACLInput!): Boolean! removeAcl(id: Int!): Boolean! # Modify Storage Path (admin only). updateStoragePath(path: String!): Boolean! # Change the current user's password. changePassword(old: String!, new: String!): Boolean! # Commit all uncommitted files in the storage path. initCommit(message: String!): Boolean! # ── Git sync (admin only) ──────────────────────────────────────────────────── # Update sync settings; the server (re)connects the remote and ticker. updateGitSync(input: GitSyncInput!): Boolean! # Merge origin/ into the current branch. result is OK, # MERGE_CONFLICT (merge left open for gitResolveMerge/gitAbortMerge) # or UNRELATED_HISTORIES (use gitResetFromRemote). gitPull: GitPullResult! # Push the current branch to origin. Fails when read-only. gitPush: Boolean! # Create a branch at HEAD and switch to it. gitCreateBranch(name: String!): Boolean! # Switch to a local branch, or track a remote-only one. gitSwitchBranch(name: String!): Boolean! # Settle conflicted paths with "ours" or "theirs" (empty paths = all), # committing the merge when nothing remains. gitResolveMerge(strategy: String!, paths: [String!]): GitResolveResult! # Throw away an in-progress merge. gitAbortMerge: Boolean! # Force the current branch to match origin. Local-only state is kept # in the returned backup branch. gitResetFromRemote: GitResetResult! # Replace the sync keypair (register the new public key as deploy key). gitRegenerateKey: GitKeyResult! # Delete an image file. deleteImage(slug: String!, filename: String!): Boolean! # Create a new folder (directory) at the specified path. createFolder(path: String!): Boolean! # Move a document from one location to another. moveDocument(oldSlug: String!, newSlug: String!): Boolean! } # ── Types ────────────────────────────────────────────────────────────────────── enum SystemStatus { OK REQUIRE_SETUP } type AppConfig { storagePath: String! ldap: LDAPConfig } type LDAPConfig { url: String! baseDN: String! adminUser: String! } type LDAPTree { users: [String!]! groups: [String!]! } type ACLEntry { id: Int! path: String! subjectType: String! subjectId: Int! effect: String! # "allow" | "deny" — deny always wins over allow canSearch: Boolean! canView: Boolean! canRead: Boolean! canEdit: Boolean! canCreate: Boolean! canDelete: Boolean! canMove: Boolean! } type LoginOptions { localEnabled: Boolean! oidcEnabled: Boolean! oidcButtonLabel: String! publicEnabled: Boolean! } type UserInfo { username: String! role: String! isLdap: Boolean! allowLogin: Boolean! createdAt: String! } type OIDCConfigView { enabled: Boolean! ready: Boolean! issuer: String! clientId: String! clientSecretSet: Boolean! redirectUrl: String! publicUrl: String! groupsClaim: String! usernameClaim: String! adminGroup: String! readerGroup: String! } type ServerDirectory { name: String! path: String! isGitRepo: Boolean! hasDocuments: Boolean! } type Document { slug: String! content: String! meta: DocumentMeta! } type DocumentMeta { slug: String! title: String! updatedAt: String! } type LDAPTestResult { success: Boolean! message: String! } type CommitEntry { hash: String! author: String! email: String! date: String! subject: String! added: Int! removed: Int! } type RepoStatus { hasUncommitted: Boolean! } type GitSyncSettings { enabled: Boolean! remoteUrl: String! liveBranch: String! readOnly: Boolean! autoSyncMinutes: Int! publicKey: String! keySet: Boolean! } type GitSyncStatus { enabled: Boolean! currentBranch: String! liveBranch: String! readOnly: Boolean! ahead: Int! behind: Int! hasUpstream: Boolean! dirty: Boolean! mergeInProgress: Boolean! conflicts: [String!]! lastSyncAt: String! lastSyncError: String! attention: Boolean! } type GitBranches { current: String! local: [String!]! remote: [String!]! } type GitPullResult { result: String! conflicts: [String!]! } type GitResolveResult { resolved: Boolean! remaining: [String!]! } type GitResetResult { backupBranch: String! } type GitKeyResult { publicKey: String! } input GitSyncInput { enabled: Boolean! remoteUrl: String! liveBranch: String! readOnly: Boolean! autoSyncMinutes: Int! } type ImageFile { name: String! url: String! size: Int! } # ── Inputs ───────────────────────────────────────────────────────────────────── input SetupInput { storagePath: String! adminUser: String! adminPass: String! ldap: LDAPInput jwtSecret: String! } input LDAPInput { url: String! baseDN: String adminUser: String! adminPass: String } type ACLSubject { id: Int! name: String! isLdap: Boolean! role: String # only present for users allowLogin: Boolean! } type ACLSubjects { users: [ACLSubject!]! groups: [ACLSubject!]! } input ACLInput { path: String! subjectType: String! subjectId: Int! effect: String # "allow" (default) | "deny" canSearch: Boolean! canView: Boolean! canRead: Boolean! canEdit: Boolean! canCreate: Boolean! canDelete: Boolean! canMove: Boolean! } input OIDCInput { enabled: Boolean! issuer: String! clientId: String! clientSecret: String # empty = keep existing redirectUrl: String publicUrl: String groupsClaim: String usernameClaim: String adminGroup: String readerGroup: String } input SaveDocumentInput { slug: String! content: String! commitMessage: String! }