Documentation
¶
Overview ¶
Package portal provides the asset portal data layer for persisting AI-generated assets (JSX dashboards, HTML reports, SVG charts).
The portal's domain vocabulary — the persisted entities, the authenticated user, the store contracts and the validation over them — is defined in internal/portal/portaldomain and aliased here. The split exists because this package must import every handler seam it registers routes from, so a seam cannot import this package back; the shared types therefore sit below both. Every name below keeps the spelling callers already use.
Index ¶
- Constants
- Variables
- func AssetIndexText(name, description string, tags []string) string
- func CollectionIndexText(name, description, sectionsText string) string
- func ContextWithUser(ctx context.Context, user *User) context.Context
- func DeriveThumbnailKey(s3Key string) string
- func DeriveThumbnailKeyVariant(s3Key, variant string) string
- func ExtensionForContentType(ct string) string
- func GenerateShareToken() (string, error)
- func HasCatalogAccess(user *User, resolver PersonaResolver, adminRoles []string) bool
- func KeepAnyShare(p SharePermission) bool
- func KeepEditorShares(p SharePermission) bool
- func ParseCallReference(source string) (string, bool)
- func RequirePortalAuth(auth *Authenticator) func(http.Handler) http.Handler
- func ResolveCollectionUpdate(coll *Collection, name, description *string) (resolvedName, resolvedDesc string, err error)
- func ResolveContentType(declared string, content []byte) string
- func SectionsText(sections []CollectionSection) string
- func ValidSharePermission(p string) bool
- func ValidateAssetName(name string) error
- func ValidateChangeSummary(s string) error
- func ValidateCollectionDescription(desc string) error
- func ValidateCollectionName(name string) error
- func ValidateContentType(ct string) error
- func ValidateContentTypeChange(existing, resolved string) error
- func ValidateDescription(desc string) error
- func ValidateEmail(email string) error
- func ValidateMaxVersions(n int) error
- func ValidateNoticeText(text string) error
- func ValidateSectionDescription(desc string) error
- func ValidateSectionTitle(title string) error
- func ValidateSections(sections []CollectionSection) error
- func ValidateShareMessage(message string) error
- func ValidateTags(tags []string) error
- type Asset
- type AssetCollectionRef
- type AssetFilter
- type AssetSearchQuery
- type AssetSearcher
- type AssetStore
- type AssetUpdate
- type AssetVersion
- type AuditMetrics
- type Authenticator
- type AuthenticatorOption
- type CallCatalog
- type CallPromoter
- type CatalogLabeler
- type ChangesetReader
- type Collection
- type CollectionConfig
- type CollectionFilter
- type CollectionItem
- type CollectionSearchQuery
- type CollectionSearcher
- type CollectionSection
- type CollectionStore
- type Deps
- type Handler
- type InsightReader
- type InsightSearcher
- type MemoryReader
- type MemoryWriter
- type MentionResolver
- type Notifier
- type PersonaInfo
- type PersonaResolver
- type PromptInfoProvider
- type PromptRegistrar
- type PromptStore
- type Provenance
- type ProvenanceCall
- type ProvenanceCapture
- type ProvenanceCapturer
- type ProvenanceRequest
- type ProvenanceToolCall
- type RateLimitConfig
- type S3Client
- type ScoredAsset
- type ScoredCollection
- type SearchCaller
- type SearchCoverage
- type SearchGroup
- type SearchHit
- type SearchQuery
- type SearchResult
- type SearchRouter
- type SessionViewer
- type Share
- type ShareAccessMode
- type ShareEvent
- type ShareKeep
- type ShareOrigin
- type SharePermission
- type ShareStore
- type ShareSummary
- type SharedAsset
- type SharedCollection
- type SharedPrompt
- type SharedPromptRef
- type SharedTargetRef
- type TargetGatherer
- type Thread
- type ThreadEvent
- type ThreadFilter
- type ThreadStore
- type ThreadUpdate
- type ThreadWithMeta
- type User
- type ValidationResponse
- type VersionStore
Constants ¶
const ( // MaxContentUploadBytes is the maximum size for content uploads (10 MB). MaxContentUploadBytes = portaldomain.MaxContentUploadBytes // MaxThumbnailUploadBytes is the maximum size for thumbnail uploads (512 KB). MaxThumbnailUploadBytes = portaldomain.MaxThumbnailUploadBytes // MaxChangeSummaryLength is the maximum length for a version change summary. MaxChangeSummaryLength = portaldomain.MaxChangeSummaryLength )
Upload ceilings for content and thumbnails.
const ( // ProvenanceKindSQL is a statement run against a query engine. ProvenanceKindSQL = portaldomain.ProvenanceKindSQL // ProvenanceKindAPI is an HTTP invocation through the API gateway. ProvenanceKindAPI = portaldomain.ProvenanceKindAPI // ProvenanceKindTool is any other data-access call the platform serves. ProvenanceKindTool = portaldomain.ProvenanceKindTool // ProvenanceOutcomeSuccess is a call that returned normally. ProvenanceOutcomeSuccess = portaldomain.ProvenanceOutcomeSuccess // ProvenanceOutcomeError is a call that failed. ProvenanceOutcomeError = portaldomain.ProvenanceOutcomeError )
Provenance call kinds and outcomes.
const ( // PermissionViewer allows read-only access. PermissionViewer = portaldomain.PermissionViewer // PermissionEditor allows read and write access. PermissionEditor = portaldomain.PermissionEditor )
Share permission levels.
const ( // OriginExplicit is a share created deliberately by an owner/editor. OriginExplicit = portaldomain.OriginExplicit // OriginPublicLinkLogin is a viewer share auto-created when a user signs // in through a public link and had no prior share for the target. OriginPublicLinkLogin = portaldomain.OriginPublicLinkLogin )
Share origins.
const ( // AccessModeRestricted admits only the named recipient // (SharedWithUserID or SharedWithEmail) and the share's creator. AccessModeRestricted = portaldomain.AccessModeRestricted // AccessModeAuthenticated admits any signed-in platform user. AccessModeAuthenticated = portaldomain.AccessModeAuthenticated // AccessModePublic admits anyone holding the token, without sign-in. AccessModePublic = portaldomain.AccessModePublic )
Share access modes.
const ( ThreadKindComment = threads.ThreadKindComment ThreadKindQuestion = threads.ThreadKindQuestion ThreadKindCorrection = threads.ThreadKindCorrection ThreadKindRating = threads.ThreadKindRating )
Thread kinds.
const ( EventTypeComment = threads.EventTypeComment EventTypeInsightLinked = threads.EventTypeInsightLinked )
Thread event types.
const ( ValidationStatePending = threads.ValidationStatePending ValidationStateValidated = threads.ValidationStateValidated ValidationStateDisputed = threads.ValidationStateDisputed )
Validation states.
const DataHubToolPrefix = "datahub_"
DataHubToolPrefix prefixes every DataHub MCP tool name.
const DefaultNoticeText = portaldomain.DefaultNoticeText
DefaultNoticeText is the notice shown on public shares when no custom text is provided. Exported so out-of-package share creators (e.g. the export adapters) apply the same default rather than re-declaring the literal.
const DefaultSearchLimit = portaldomain.DefaultSearchLimit
DefaultSearchLimit is the top-K returned when a ranked query does not specify a limit.
const ThreadStatusResolved = threads.ThreadStatusResolved
ThreadStatusResolved is re-exported from pkg/portal/threads.
Variables ¶
var ( NewPostgresThreadStore = threads.NewPostgresThreadStore NewThreadEventID = threads.NewThreadEventID )
Thread data-layer constructors.
Functions ¶
func AssetIndexText ¶ added in v1.81.0
AssetIndexText composes the text an asset is embedded and lexically indexed on for relevance search: its name, description, and tags.
func CollectionIndexText ¶ added in v1.81.0
CollectionIndexText composes the text a collection is embedded and lexically indexed on: its name, description, and the denormalized section text.
func ContextWithUser ¶ added in v1.95.0
ContextWithUser returns a copy of ctx carrying the authenticated user, the value GetUser reads. Exported so handlers split into sibling packages (e.g. internal/httpserver/datahubapi) can be exercised with an authenticated principal.
func DeriveThumbnailKey ¶ added in v1.40.1
DeriveThumbnailKey replaces the filename in an S3 key with ".thumbnail.png" (the light/default variant).
func DeriveThumbnailKeyVariant ¶ added in v1.86.3
DeriveThumbnailKeyVariant replaces the filename in an S3 key with the thumbnail filename for the given variant ("dark" -> .thumbnail_dark.png, anything else -> .thumbnail.png).
func ExtensionForContentType ¶ added in v1.43.0
ExtensionForContentType returns the file extension used in an asset's object key for a content type.
func GenerateShareToken ¶ added in v1.100.2
GenerateShareToken generates a cryptographically random hex token for share links. Exported so out-of-package share creators (e.g. the export adapters) mint tokens with the same length and encoding as portal-issued shares.
func HasCatalogAccess ¶ added in v1.119.0
func HasCatalogAccess(user *User, resolver PersonaResolver, adminRoles []string) bool
HasCatalogAccess reports whether a user may read the DataHub catalog: their persona grants any DataHub tool (read or write), or they are an admin. It is the one rule behind every catalog read the portal serves — the DataHub REST surface (internal/httpserver/datahubapi) and the knowledge-page reference labels (#1159) — so a persona denied the catalog is denied it on both, and the portal never discloses more than the persona-filtered MCP surface would.
func KeepAnyShare ¶ added in v1.86.0
func KeepAnyShare(p SharePermission) bool
KeepAnyShare keeps shares at any permission.
func KeepEditorShares ¶ added in v1.86.0
func KeepEditorShares(p SharePermission) bool
KeepEditorShares keeps only editor-permission shares.
func ParseCallReference ¶ added in v1.121.0
ParseCallReference returns the event id a source string names, accepting the bare id and the mcp:call:<id> reference form alike.
func RequirePortalAuth ¶
func RequirePortalAuth(auth *Authenticator) func(http.Handler) http.Handler
RequirePortalAuth creates middleware that enforces portal authentication.
func ResolveCollectionUpdate ¶ added in v1.121.0
func ResolveCollectionUpdate(coll *Collection, name, description *string) (resolvedName, resolvedDesc string, err error)
ResolveCollectionUpdate merges a partial name/description update over an existing collection and validates the result, returning the values to store. A nil field leaves the stored value untouched, which the store's full-record Update requires the caller to resolve.
It is exported because the admin route updates the same collections under a different authorization rule (#1292): one merge means an admin edit can never write a name or description the owner's own edit would have refused.
func ResolveContentType ¶ added in v1.110.0
ResolveContentType returns the content type to store for content whose author declared declared.
func SectionsText ¶ added in v1.81.0
func SectionsText(sections []CollectionSection) string
SectionsText flattens a collection's sections into the denormalized sections_text column.
func ValidSharePermission ¶ added in v1.42.0
ValidSharePermission checks whether a permission string is valid.
func ValidateAssetName ¶
ValidateAssetName checks that a name is non-empty and within length limits.
func ValidateChangeSummary ¶ added in v1.43.1
ValidateChangeSummary checks that a change summary is within length limits.
func ValidateCollectionDescription ¶ added in v1.47.0
ValidateCollectionDescription checks collection description length.
func ValidateCollectionName ¶ added in v1.47.0
ValidateCollectionName checks that a collection name is valid.
func ValidateContentType ¶
ValidateContentType checks that a content type is present and is one the platform stores for content that arrives as a string.
func ValidateContentTypeChange ¶ added in v1.117.0
ValidateContentTypeChange checks the type a content update resolved to against the type the asset already carries.
func ValidateDescription ¶
ValidateDescription checks that a description is within length limits.
func ValidateEmail ¶ added in v0.35.9
ValidateEmail checks that an email address has a basic valid format.
func ValidateMaxVersions ¶ added in v1.124.1
ValidateMaxVersions checks a per-asset version-retention cap: 0 asks for unlimited history, any positive number is a cap, and a negative number is refused.
func ValidateNoticeText ¶ added in v1.39.0
ValidateNoticeText checks that notice text is within length limits.
func ValidateSectionDescription ¶ added in v1.47.0
ValidateSectionDescription checks section description length.
func ValidateSectionTitle ¶ added in v1.47.0
ValidateSectionTitle checks section title length.
func ValidateSections ¶ added in v1.47.0
func ValidateSections(sections []CollectionSection) error
ValidateSections checks sections count and content validity.
func ValidateShareMessage ¶ added in v1.118.0
ValidateShareMessage checks the sharer's optional plain-text note.
func ValidateTags ¶
ValidateTags checks tag count and individual tag length.
Types ¶
type AssetCollectionRef ¶ added in v1.47.0
type AssetCollectionRef = portaldomain.AssetCollectionRef
AssetCollectionRef is a lightweight reference to a collection that contains an asset.
type AssetFilter ¶
type AssetFilter = portaldomain.AssetFilter
AssetFilter defines filtering criteria for listing assets.
type AssetSearchQuery ¶ added in v1.81.0
type AssetSearchQuery = portaldomain.AssetSearchQuery
AssetSearchQuery describes a relevance ranking request over saved assets.
type AssetSearcher ¶ added in v1.81.0
type AssetSearcher = portaldomain.AssetSearcher
AssetSearcher ranks the caller's assets by relevance to a query.
type AssetStore ¶
type AssetStore = portaldomain.AssetStore
AssetStore persists and queries portal assets.
func NewNoopAssetStore ¶
func NewNoopAssetStore() AssetStore
NewNoopAssetStore creates a no-op AssetStore for use when no database is available.
func NewPostgresAssetStore ¶
func NewPostgresAssetStore(db *sql.DB, producers producedby.Store, opts ...indexjobs.StoreOption) AssetStore
NewPostgresAssetStore creates a new PostgreSQL asset store. producers records what produced each asset (#1569) and may be nil, which records nothing. Pass indexjobs.WithProducer to have asset writes enqueue their own index job instead of waiting for the reconciler's next sweep.
type AssetUpdate ¶
type AssetUpdate = portaldomain.AssetUpdate
AssetUpdate holds mutable fields for updating an asset.
type AssetVersion ¶ added in v1.43.0
type AssetVersion = portaldomain.AssetVersion
AssetVersion records a single version of an asset's content.
type AuditMetrics ¶ added in v0.36.0
type AuditMetrics interface {
Timeseries(ctx context.Context, filter audit.TimeseriesFilter) ([]audit.TimeseriesBucket, error)
Breakdown(ctx context.Context, filter audit.BreakdownFilter) ([]audit.BreakdownEntry, error)
Overview(ctx context.Context, filter audit.MetricsFilter) (*audit.Overview, error)
}
AuditMetrics provides aggregate audit metrics scoped to individual users.
type Authenticator ¶
type Authenticator struct {
// contains filtered or unexported fields
}
Authenticator wraps the platform's middleware.Authenticator chain for HTTP portal requests. Unlike the admin authenticator, it does not require a specific persona — any authenticated user can access the portal.
func NewAuthenticator ¶
func NewAuthenticator(auth middleware.Authenticator, opts ...AuthenticatorOption) *Authenticator
NewAuthenticator creates a Authenticator.
func (*Authenticator) Authenticate ¶
func (pa *Authenticator) Authenticate(r *http.Request) (*User, error)
Authenticate resolves the caller via session cookie (CSRF-enforced on state-changing methods) first, then falls back to token auth. A CSRF failure on a valid cookie is deferred, not fatal: a CSRF-exempt token (which a cross-site attacker cannot supply) may still authenticate the request, and only when none does is the rejection surfaced (→ 403).
func (*Authenticator) IssueCSRF ¶ added in v1.96.0
func (pa *Authenticator) IssueCSRF(subject string) string
IssueCSRF returns a CSRF token bound to subject, or "" when cookie auth is not configured.
type AuthenticatorOption ¶
type AuthenticatorOption func(*Authenticator)
AuthenticatorOption configures the portal authenticator.
func WithBrowserAuth ¶
func WithBrowserAuth(ba *browsersession.Authenticator) AuthenticatorOption
WithBrowserAuth adds cookie-based authentication.
type CallCatalog ¶ added in v1.121.0
CallCatalog reads the recorded data-access calls. Aliased to the seam's own declaration rather than restated so the two cannot drift, and identical to the operator surface's alias: there is one catalog, and the portal's face of it differs only in being scoped to the caller.
type CallPromoter ¶ added in v1.121.0
type CallPromoter = callrecord.Promoter
CallPromoter publishes a record its owner chose to publish.
type CatalogLabeler ¶ added in v1.119.0
CatalogLabeler resolves catalog (DataHub) entity URNs to display names in one batch. It is satisfied by the DataHub bridge's labeler; the portal states only the shape it needs so this package keeps no DataHub dependency.
type ChangesetReader ¶ added in v1.84.0
type ChangesetReader = feedbackapi.ChangesetReader
ChangesetReader provides read access to knowledge changesets, used to surface the thread -> insight -> changeset chain on a feedback thread.
type Collection ¶ added in v1.47.0
type Collection = portaldomain.Collection
Collection represents a curated, ordered group of assets organized into sections.
type CollectionConfig ¶ added in v1.47.0
type CollectionConfig = portaldomain.CollectionConfig
CollectionConfig holds extensible per-collection settings.
type CollectionFilter ¶ added in v1.47.0
type CollectionFilter = portaldomain.CollectionFilter
CollectionFilter defines filtering criteria for listing collections.
type CollectionItem ¶ added in v1.47.0
type CollectionItem = portaldomain.CollectionItem
CollectionItem is an ordered reference to an asset within a section.
type CollectionSearchQuery ¶ added in v1.81.0
type CollectionSearchQuery = portaldomain.CollectionSearchQuery
CollectionSearchQuery describes a relevance ranking request over collections.
type CollectionSearcher ¶ added in v1.81.0
type CollectionSearcher = portaldomain.CollectionSearcher
CollectionSearcher ranks the caller's collections by relevance to a query.
type CollectionSection ¶ added in v1.47.0
type CollectionSection = portaldomain.CollectionSection
CollectionSection is an ordered section within a collection.
type CollectionStore ¶ added in v1.47.0
type CollectionStore = portaldomain.CollectionStore
CollectionStore persists and queries portal collections.
func NewNoopCollectionStore ¶ added in v1.47.0
func NewNoopCollectionStore() CollectionStore
NewNoopCollectionStore creates a no-op CollectionStore for use when no database is available.
func NewPostgresCollectionStore ¶ added in v1.47.0
func NewPostgresCollectionStore(db *sql.DB, opts ...indexjobs.StoreOption) CollectionStore
NewPostgresCollectionStore creates a new PostgreSQL collection store. Pass indexjobs.WithProducer to have collection writes enqueue their own index job instead of waiting for the reconciler's next sweep.
type Deps ¶
type Deps struct {
AssetStore AssetStore
VersionStore VersionStore
CollectionStore CollectionStore
ThreadStore ThreadStore
KnowledgePageStore knowledgepage.Store
// RestoreBuiltinPages un-hides the operator-hidden built-in knowledge pages
// and reconciles them to the running release, returning how many came back
// (#1390). Wired by the composition root (the reconcile lives in an
// internal seam this package cannot import); nil leaves the route
// unregistered.
RestoreBuiltinPages func(ctx context.Context) (int, error)
// KnowledgePageDedupThreshold is the create-time duplicate-gate threshold (#705)
// the REST create path shares with the MCP apply path. 0 disables the gate. The
// platform resolves it (default/disabled) before wiring; the handler treats it as
// final.
KnowledgePageDedupThreshold float64
S3Client S3Client
S3Bucket string
PublicBaseURL string
RateLimit RateLimitConfig
// RateLimitResolver attributes the client IP for the public viewer's
// rate limiter with trusted-proxy awareness (#904). nil yields the safe
// trust-none default (direct peer address; X-Forwarded-For ignored), so an
// attacker cannot mint unlimited per-IP buckets with a spoofed header.
RateLimitResolver *ratelimit.Resolver
OIDCEnabled bool
AdminRoles []string // roles that grant admin access in the portal
PromptStore PromptStore
PromptRegistrar PromptRegistrar
PromptInfoProvider PromptInfoProvider
AuditMetrics AuditMetrics
// SessionViewer reads sessions off the audit log. The portal serves it
// scoped to the caller: the same read model the operator surface uses,
// narrowed to the sessions the reader ran themselves. nil (no database)
// leaves the routes unregistered.
SessionViewer SessionViewer
// CallCatalog is the record of the data-access calls the caller made
// (#1321), served scoped to them. nil (no database) leaves the routes
// unregistered.
CallCatalog CallCatalog
// CallPromoter publishes a record its owner chose to publish. nil leaves
// the promote and reject actions unregistered.
CallPromoter *CallPromoter
InsightStore InsightReader
ChangesetReader ChangesetReader
MemoryStore MemoryReader
MemoryWriter MemoryWriter
EmbeddingProvider embedding.Provider
PersonaResolver PersonaResolver
// PortalAppAdmits reports whether a signed-in caller holding these roles
// would be served the portal application at /portal/ — the SPA is mounted
// in this build, and the shell's own gate admits the account. The public
// share viewer asks before sending a signed-in reader there instead of
// rendering the public page (#1473).
//
// Supplied by the composition root, the only place that knows both facts.
// nil means no portal application is served for this handler, and no share
// is ever redirected.
PortalAppAdmits func(roles []string) bool
// SearchRouter backs GET /api/v1/portal/search, the REST surface over the
// unified knowledge federation. nil disables the endpoint (no searchable
// source configured).
SearchRouter SearchRouter
// DataHubRegistrar, when set, registers the portal DataHub Catalog and Context
// Docs REST routes (#718) onto the portal mux. It is provided by cmd wiring
// (internal/httpserver/datahubapi.Handler.Register) so the DataHub feature lives in its
// own package; nil leaves the /api/v1/portal/datahub/* routes unregistered.
DataHubRegistrar func(*http.ServeMux)
// OnAssetDeleted, when set, is called after an asset is deleted so the
// tables registered over its file are dropped (#1327). A delete is soft
// and leaves the object in place, so a table still pointing at it would
// keep serving rows out of a schema the owner can no longer see. Nil on a
// deployment that cannot register tables.
OnAssetDeleted func(context.Context, string)
// OnAssetRevised, when set, is called after a new version of an asset's
// content is written -- an edit or a revert -- so the tables registered
// over its file follow it (#1536). It returns what happened to each table,
// which the response carries: a following table now reads the new version,
// a pinned one is behind it. The write is never failed by it. Nil on a
// deployment that cannot register tables.
OnAssetRevised func(ctx context.Context, id string, version int) []string
// CatalogLabeler names the DataHub governance entities a knowledge page
// references (#1159), so a citation to a glossary term, a tag, or a domain
// renders as its display name instead of the generated key inside its URN.
// It is provided by the same cmd wiring as DataHubRegistrar; nil (no DataHub
// connection) falls back to the name derivable from the URN itself.
CatalogLabeler CatalogLabeler
// MentionResolver filters the @-mentions written in a thread comment to
// the people who can open the thread's target (#627). nil disables
// mentions (no database): tokens stay ordinary text and notify nobody.
MentionResolver MentionResolver
// Authenticator resolves a logged-in user from a public (unauthenticated)
// request so the public viewer can auto-promote a signed-in viewer to a
// derived share. Optional; nil disables auto-promote.
Authenticator *Authenticator
// Platform brand (far right of public viewer header)
BrandName string // display name (default: "MCP Data Platform")
// BrandLogoHTML is the header logo as markup: an <img> element sourced at
// the configured logo URL, or an inline <svg> an MCP App config named.
// Empty renders the bundled default icon.
BrandLogoHTML string
BrandURL string // link URL (e.g., "https://plexara.io"); empty = no link
// Implementor brand (far left of public viewer header, optional)
ImplementorName string // display name (e.g., "ACME Corp"); empty = hidden
// ImplementorLogoHTML is the logo as markup, on the same terms as
// BrandLogoHTML; empty = hidden.
ImplementorLogoHTML string
ImplementorURL string // link URL; empty = no link
// Notifier receives share and thread trigger events (issue #631). nil
// disables email notifications; implementations log their own failures
// and never fail the originating request.
Notifier Notifier
// denial pages, one-time view links, and guest sessions. nil keeps the
// pre-#1001 plain-text denials and registers no guest routes.
ShareGuest *shareguest.Service
// NotificationRegistrar, when set, registers the self-scoped
// notification-preference REST routes onto the portal's authenticated
// mux (the DataHubRegistrar pattern): the feature lives with the
// notification substrate, not in this package. nil leaves the
// /api/v1/portal/notification-prefs routes unregistered.
NotificationRegistrar func(*http.ServeMux)
// ContentRefs records the managed resources an asset's content
// references (#1474). Every content read this handler serves rewrites the
// declared mcp:// URIs into the serving URL below; nil (no database, or no
// managed-resource layer) leaves content served exactly as stored, which
// is what an asset with no references gets anyway.
//
// Its type is not aliased into this package's namespace, unlike the store
// contracts around it: pkg/portal sits exactly at the exported-surface
// budget, and this is an implementation package rather than a supported
// import surface (docs/library/stability.md), so the composition root
// names the internal type directly.
ContentRefs assetrefs.Store
// ResourceReader and ResourceBlobs read a referenced resource's metadata
// and its bytes. They are the managed-resource layer's store and object
// client, not the portal's: a reference points at a resource, which lives
// in its own bucket. Either nil leaves the serving route unregistered.
ResourceReader assetrefs.Resources
ResourceBlobs assetrefs.BlobReader
// ResourceS3Bucket is the bucket managed-resource blobs live in.
ResourceS3Bucket string
// Producers is the record of what wrote each asset and each managed
// resource (#1569), read by the producer routes from the target end. Nil
// (no database) leaves those routes unregistered. Its type is named
// directly for the reason ContentRefs's is.
Producers producedby.Store
// ScriptNames resolves a script producer to the name it carries now, and
// so to whether it still exists at all. Nil reports every script producer
// as existing.
ScriptNames producerapi.ScriptNames
}
Deps holds dependencies for the portal handler.
type Handler ¶
type Handler struct {
// contains filtered or unexported fields
}
Handler provides portal REST API endpoints.
func NewHandler ¶
NewHandler creates a new portal API handler.
type InsightReader ¶ added in v0.36.0
type InsightReader interface {
List(ctx context.Context, filter knowledge.InsightFilter) ([]knowledge.Insight, int, error)
Stats(ctx context.Context, filter knowledge.InsightFilter) (*knowledge.InsightStats, error)
// Get returns a single insight by id, used to surface a knowledge page's
// source-insight lineage (#678). A drained or deleted insight returns an error.
Get(ctx context.Context, id string) (*knowledge.Insight, error)
}
InsightReader provides read-only access to user insights.
type InsightSearcher ¶ added in v1.80.0
type InsightSearcher = knowledge.InsightSearcher
InsightSearcher is the optional relevance-search capability of the insight store, declared canonically in the knowledge package next to its query and result types. The knowledge-search route (and the recall_insight tool) are registered only when the wired InsightStore satisfies it; the memory-backed adapter does, the legacy separate-table store does not.
type MemoryReader ¶ added in v1.52.0
type MemoryReader interface {
List(ctx context.Context, filter memory.Filter) ([]memory.Record, int, error)
HybridSearch(ctx context.Context, q memory.HybridQuery) ([]memory.ScoredRecord, error)
LexicalSearch(ctx context.Context, q memory.LexicalQuery) ([]memory.ScoredRecord, error)
}
MemoryReader provides read-only access to user memory records. The search methods back the portal's per-user "my knowledge" search: both queries are scoped to the caller via CreatedBy server-side, so a user can never search another user's records.
type MemoryWriter ¶ added in v1.88.0
type MemoryWriter = feedbackapi.MemoryWriter
MemoryWriter inserts memory records. It backs the "capture feedback as an insight" path: a reviewer turns a feedback thread into a pending, knowledge-dimension memory record that enters the apply_knowledge review queue. The full memory.Store satisfies it; the portal only needs Insert.
type MentionResolver ¶ added in v1.114.0
type MentionResolver = feedbackapi.MentionResolver
MentionResolver returns the addresses a comment body delivers an @-mention to on a thread target: the names written in the body, minus the author's own address, filtered to the people who can open that target. Implemented by pkg/portal/mention, which the composition root injects; a nil resolver disables mentions (no database), leaving every token ordinary text.
type Notifier ¶ added in v1.103.0
type Notifier interface {
NotifyShare(ctx context.Context, share *Share, ev ShareEvent)
// NotifyThreadEvent fires after a successful thread create or event
// append. thread carries the target reference; body is the comment text;
// mentioned carries the @-mentions the body delivers, already filtered to
// people who can open the target (#627). Mentioned people are notified as
// mentions -- their own category, which a recipient can keep on while
// muting general thread activity -- and are left out of the general
// notification, so one comment never sends the same person two emails.
NotifyThreadEvent(ctx context.Context, thread *Thread, actorEmail, body string, mentioned []string)
}
Notifier receives the portal's notification trigger events (issue #631): direct shares and feedback-thread activity. Implementations queue email notifications and must never fail the originating request -- both methods are fire-and-forget, logging their own errors. The share kind is one of "asset", "collection", or "prompt". A nil Notifier disables notifications.
The implementation lives with the notification delivery substrate (internal/platform/notifydelivery); portal only fires the events.
type PersonaInfo ¶ added in v0.36.0
type PersonaInfo struct {
Name string
Tools []string // resolved tool names from Allow/Deny patterns
}
PersonaInfo holds resolved persona details for the current user.
type PersonaResolver ¶ added in v0.36.0
type PersonaResolver func(roles []string) *PersonaInfo
PersonaResolver resolves a user's roles to their persona info.
type PromptInfoProvider ¶ added in v1.51.0
type PromptInfoProvider interface {
AllPromptInfos() []registry.PromptInfo
}
PromptInfoProvider returns metadata about system-registered prompts.
type PromptRegistrar ¶ added in v1.51.0
type PromptRegistrar interface {
RegisterRuntimePrompt(p *prompt.Prompt)
UnregisterRuntimePrompt(name string)
}
PromptRegistrar registers/unregisters prompts with the live MCP server.
type PromptStore ¶ added in v1.51.0
PromptStore provides prompt persistence for the portal: exactly the prompt store contract, aliased so portal deps read naturally.
type Provenance ¶
type Provenance = portaldomain.Provenance
Provenance records which calls produced an asset.
type ProvenanceCall ¶ added in v1.121.0
type ProvenanceCall = portaldomain.ProvenanceCall
ProvenanceCall is one captured call in a capture's snapshot.
type ProvenanceCapture ¶ added in v1.121.0
type ProvenanceCapture = portaldomain.ProvenanceCapture
ProvenanceCapture is one recording of the calls an asset was built from.
type ProvenanceCapturer ¶ added in v1.121.0
type ProvenanceCapturer = portaldomain.ProvenanceCapturer
ProvenanceCapturer resolves a write's sources into a capture.
type ProvenanceRequest ¶ added in v1.121.0
type ProvenanceRequest = portaldomain.ProvenanceRequest
ProvenanceRequest asks for a capture of the calls behind one asset write.
type ProvenanceToolCall ¶
type ProvenanceToolCall = portaldomain.ProvenanceToolCall
ProvenanceToolCall records a single tool invocation in the provenance chain. Pre-#1320 shape, still read from assets written under it.
type RateLimitConfig ¶
type RateLimitConfig = viewerlimit.Config
RateLimitConfig aliases the public viewer rate limiter's config, which lives in internal/portal/viewerlimit with the implementation. The alias keeps the portal's public API spelling stable for existing callers.
type S3Client ¶
type S3Client = portaldomain.S3Client
S3Client abstracts the S3 operations needed by the portal toolkit.
type ScoredAsset ¶ added in v1.81.0
type ScoredAsset = portaldomain.ScoredAsset
ScoredAsset pairs an asset with its relevance score in [0,1].
type ScoredCollection ¶ added in v1.81.0
type ScoredCollection = portaldomain.ScoredCollection
ScoredCollection pairs a collection with its relevance score in [0,1].
type SearchCaller ¶ added in v1.88.0
SearchCaller is the resolved requester identity per-user providers scope on.
type SearchCoverage ¶ added in v1.88.0
type SearchCoverage struct {
Source string `json:"source"`
Matched int `json:"matched"`
Shown int `json:"shown"`
Withheld int `json:"withheld,omitempty"`
}
SearchCoverage reports, per source, how many records matched versus how many are shown, the anti-tunnel signal that breadth exists beyond the display set, plus how many the caller's persona hid (#1108) so "nothing matched" and "matches you may not see" render differently.
type SearchGroup ¶ added in v1.88.0
SearchGroup is one source's slice of the balanced display set.
type SearchHit ¶ added in v1.88.0
type SearchHit struct {
Text string `json:"text"`
Source string `json:"source"`
Ref string `json:"ref"`
Score float64 `json:"score"`
Status string `json:"status,omitempty"`
EntityURNs []string `json:"entity_urns,omitempty"`
Dimension string `json:"dimension,omitempty"`
}
SearchHit is one matched record. The JSON shape matches the MCP search tool's hit so the portal and agent surfaces render identical results.
type SearchQuery ¶ added in v1.88.0
type SearchQuery struct {
Intent string
EntityURNs []string
Status string
Sources []string
Caller SearchCaller
Limit int
}
SearchQuery is one unified search. Intent is natural-language text; EntityURNs is an exact entity-keyed lookup; at least one is set. Caller is the per-user scope boundary. These fields mirror knowledge.Query; the adapter in main maps between them.
type SearchResult ¶ added in v1.88.0
type SearchResult struct {
Groups []SearchGroup
Coverage []SearchCoverage
Ranking string
UnknownSources []string
// WithheldNotice explains, in one line, results the caller's persona hid
// because they belong to connections it is not granted (#1108). Empty when
// nothing was withheld. The adapter builds it from the router's coverage so
// the portal and the MCP search tool render identical copy.
WithheldNotice string
}
SearchResult is the grouped-by-source response. It mirrors knowledge.Result.
type SearchRouter ¶ added in v1.88.0
type SearchRouter interface {
Search(ctx context.Context, q SearchQuery) (SearchResult, error)
}
SearchRouter is the unified knowledge-search federation behind the portal's GET /api/v1/portal/search endpoint. It is a portal-local interface (rather than a direct dependency on pkg/knowledge) because that package already imports pkg/portal for the asset and knowledge-page stores; importing it back would form a cycle. main wires a thin adapter over *knowledge.Router that maps to these types, so the REST surface returns the same grouped, scope-enforced result set as the MCP search tool.
type SessionViewer ¶ added in v1.121.0
type SessionViewer = sessionapi.Store
SessionViewer reads the audit-derived session record. Aliased to the seam's declaration rather than restated so the two cannot drift, and identical to the operator surface's alias: there is one read model, and the portal's face of it differs only in being scoped to the caller.
type Share ¶
type Share = portaldomain.Share
Share represents a share link for an asset, collection, or prompt.
type ShareAccessMode ¶ added in v1.104.0
type ShareAccessMode = portaldomain.ShareAccessMode
ShareAccessMode determines who may open a share token.
type ShareEvent ¶ added in v1.118.0
type ShareEvent struct {
Kind string
// ItemID and ItemTitle identify the shared item.
// ValidateShareMessage. Empty means no note.
Message string
}
ShareEvent carries what a share notification is about: the item shared and the sharer's optional personal note.
The note lives here rather than on Share because it is not part of the share: it is never persisted, never shown in the viewer, and reaches only the one email the share produces. A share created with notify off carries no note anywhere.
type ShareKeep ¶ added in v1.86.0
type ShareKeep = feedbackapi.ShareKeep
ShareKeep decides whether a share grant counts toward a gathered target set. KeepEditorShares is the "I can act on it" scope (worklist, MCP agent); KeepAnyShare is the "I can view it" scope (activity feed).
type ShareOrigin ¶ added in v1.84.0
type ShareOrigin = portaldomain.ShareOrigin
ShareOrigin records how a share came to exist.
type SharePermission ¶ added in v1.42.0
type SharePermission = portaldomain.SharePermission
SharePermission defines the access level for a share recipient.
type ShareStore ¶
type ShareStore = portaldomain.ShareStore
ShareStore persists and queries share links for assets, collections, and prompts.
func NewNoopShareStore ¶
func NewNoopShareStore() ShareStore
NewNoopShareStore creates a no-op ShareStore for use when no database is available.
func NewPostgresShareStore ¶
func NewPostgresShareStore(db *sql.DB) ShareStore
NewPostgresShareStore creates a new PostgreSQL share store.
type ShareSummary ¶ added in v0.37.0
type ShareSummary = portaldomain.ShareSummary
ShareSummary indicates what kinds of active shares exist for an asset.
type SharedAsset ¶
type SharedAsset = portaldomain.SharedAsset
SharedAsset combines an Asset with share metadata for "shared with me" results.
type SharedCollection ¶ added in v1.47.0
type SharedCollection = portaldomain.SharedCollection
SharedCollection combines a Collection with share metadata.
type SharedPrompt ¶ added in v1.81.0
type SharedPrompt struct {
}
SharedPrompt is a prompt shared with the current user, with share metadata, for the "Shared With Me" listing.
type SharedPromptRef ¶ added in v1.81.0
type SharedPromptRef = portaldomain.SharedPromptRef
SharedPromptRef references a prompt shared with a user along with share metadata.
type SharedTargetRef ¶ added in v1.121.0
type SharedTargetRef = portaldomain.SharedTargetRef
SharedTargetRef is one share grant to a named recipient, of any artifact kind.
type TargetGatherer ¶ added in v1.86.0
type TargetGatherer = feedbackapi.TargetGatherer
TargetGatherer gathers the asset/collection ids a single user can reach, bundling the stores and identity so callers (REST worklist/activity feed, the manage_feedback MCP tool) build it once and ask for asset or collection ids with the desired share scope.
type ThreadEvent ¶ added in v1.84.0
type ThreadEvent = threads.ThreadEvent
ThreadEvent is re-exported from pkg/portal/threads.
type ThreadFilter ¶ added in v1.84.0
type ThreadFilter = threads.ThreadFilter
ThreadFilter is re-exported from pkg/portal/threads.
type ThreadStore ¶ added in v1.84.0
type ThreadStore = threads.ThreadStore
ThreadStore is re-exported from pkg/portal/threads.
type ThreadUpdate ¶ added in v1.84.0
type ThreadUpdate = threads.ThreadUpdate
ThreadUpdate is re-exported from pkg/portal/threads.
type ThreadWithMeta ¶ added in v1.84.0
type ThreadWithMeta = threads.ThreadWithMeta
ThreadWithMeta is re-exported from pkg/portal/threads.
type User ¶
User holds information about the authenticated portal user. It is defined with the authorization core because it is the subject of every permission check the portal makes.
type ValidationResponse ¶ added in v1.84.0
type ValidationResponse = threads.ValidationResponse
ValidationResponse is re-exported from pkg/portal/threads.
type VersionStore ¶ added in v1.43.0
type VersionStore = portaldomain.VersionStore
VersionStore persists and queries asset version history.
func NewNoopVersionStore ¶ added in v1.43.0
func NewNoopVersionStore() VersionStore
NewNoopVersionStore creates a no-op VersionStore for use when no database is available.
func NewPostgresVersionStore ¶ added in v1.43.0
func NewPostgresVersionStore(db *sql.DB, s3Client S3Client, maxVersions *int, producers producedby.Store) VersionStore
NewPostgresVersionStore creates a new PostgreSQL asset version store. s3Client deletes the objects of versions the retention cap prunes and may be nil in database-only mode, where the prune still trims the table; maxVersions is the deployment default a per-asset override supersedes, nil selecting the platform default of 100; producers records what produced each version and may be nil.
Source Files
¶
- assetrefs.go
- auth.go
- calls.go
- collection_handler.go
- domain.go
- feedback.go
- handler.go
- http.go
- knowledge_page_graph_handler.go
- knowledge_page_handler.go
- knowledge_page_refs_handler.go
- notification_handler.go
- prompt_handler.go
- public.go
- ratelimit.go
- search_handler.go
- sessions.go
- share_access.go
- store.go
- thread_aliases.go
- unified_search_handler.go
Directories
¶
| Path | Synopsis |
|---|---|
|
Package knowledgepage is the store and ranked-search backend for canonical business/domain knowledge pages (#633): org-shared markdown documents stored inline in Postgres so their content is vector- and full-text searchable.
|
Package knowledgepage is the store and ranked-search backend for canonical business/domain knowledge pages (#633): org-shared markdown documents stored inline in Postgres so their content is vector- and full-text searchable. |
|
Package mention implements @-mention tagging on portal feedback threads (#627).
|
Package mention implements @-mention tagging on portal feedback threads (#627). |
|
Package s3adapter adapts an mcp-s3 client to the portal.S3Client interface used by the portal handler for blob storage.
|
Package s3adapter adapts an mcp-s3 client to the portal.S3Client interface used by the portal handler for blob storage. |
|
Package shareaccess decides who may open a portal share token.
|
Package shareaccess decides who may open a portal share token. |
|
Package shareguest gives the named recipient of an email share a way in without a platform account (#1001).
|
Package shareguest gives the named recipient of an email share a way in without a platform account (#1001). |
|
Package threads holds the portal feedback-thread data layer: the Thread types and constants, the ThreadStore interface, its PostgreSQL implementation, and the filter/query helpers.
|
Package threads holds the portal feedback-thread data layer: the Thread types and constants, the ThreadStore interface, its PostgreSQL implementation, and the filter/query helpers. |