34 Commits
Author SHA1 Message Date
james.maesandClaude Fable 5.2 04d04adc6e perf(security): authorize each distinct parent once per child result page
maven / build (push) Successful in 7m15s
build / maven (push) Successful in 7m15s
ParentRowCustomizer and AttachmentPreviewCustomizer read the parent of
every child row to decide whether the row is visible, so rows that share a
parent repeated the same read: 61 tasks on two parents ran 61 parent reads
(TagLookupStatementBudgetTest), now 2. The answer is kept only for the one
postQuery call, where the session and transaction cannot change.

Also correct the README: the Tags field is selectable.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
2026-11-10 15:58:11 -06:00
james.maesandClaude Fable 5.2 de922d7e86 perf(tags): no assignment lookup for tables that have no tags
Core selects the Tags virtual field for every query or get that names no
fields, so every such read of a TAGS-enabled table ran one
collaboration_record_tag statement, including reads made one record at a
time and tables that were never tagged. Measured with 600 added parents
(TagLookupStatementBudgetTest): a 602-row list ran 2 statements, 600 gets
ran 600 and 100 single-record updates ran 100; now 1 probe, then 0.

TaggedTables remembers, per node and per table, whether any assignment
exists (core Memoization registered with ClusterCaches, 30 s by default,
withTagLookupCacheSeconds, 0 disables). Writing an assignment clears it at
once and after commit and publishes memo-invalidate. The probe ignores row
locks and returns no data, so the answer is the same for every session.
Tables with assignments are read as before: one lookup per 500 parents.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
2026-11-10 15:58:11 -06:00
james.maesandClaude Sonnet 5.5 024cfc21a9 release: prepare Collaboration 1.0 (Core RC.22 BOM, Redis RC.1, current status docs)
QRun-IO/ci-policy: ci / node-8 (pull_request) Skipped
QRun-IO/ci-policy: ci / node-9 (pull_request) Skipped
QRun-IO/ci-policy: ci / node-10 (pull_request) Skipped
QRun-IO/ci-policy: ci / node-playwright-11 (pull_request) Skipped
QRun-IO/ci-policy: ci / repository-policy-12 (pull_request) Skipped
QRun-IO/ci-policy: ci / source-config-13 (pull_request) Skipped
QRun-IO/ci-policy: ci / source-config-14 (pull_request) Skipped
QRun-IO/ci-policy: ci / android-0 (pull_request) Skipped
QRun-IO/ci-policy: ci / original-business (pull_request) Skipped
QRun-IO/ci-policy: ci / original-mcp (pull_request) Skipped
QRun-IO/ci-policy: ci / original-voyage (pull_request) Skipped
QRun-IO/ci-policy: ci / original-cli (pull_request) Skipped
QRun-IO/ci-policy: ci / not-enrolled (pull_request) Skipped
QRun-IO/ci-policy: ci / Scoped workflow [workflow 1e25bb5a243dfdcd95d4b9a4f780200ff8c8778a] (pull_request) Successful in 12s
QRun-IO/ci-policy: ci / shared-pipeline (pull_request) Skipped
QRun-IO/ci-policy: native / native-result (pull_request) Successful in 9s
QRun-IO/ci-policy: ci / fork-guard (pull_request) Skipped
maven / build (push) Successful in 11m4s
build / maven (push) Successful in 11m4s
QRun-IO/ci-policy: ci / ci-result (pull_request) Successful in 6s
QRun-IO/ci-policy: native / fork-deny (pull_request) Skipped
QRun-IO/ci-policy: native / dotnet-0 (pull_request) Skipped
QRun-IO/ci-policy: ci / head-profile (pull_request) Skipped
QRun-IO/ci-policy: ci / repository-policy (pull_request) Skipped
QRun-IO/ci-policy: ci / application-template-0 (pull_request) Skipped
QRun-IO/ci-policy: ci / gradle-1 (pull_request) Skipped
QRun-IO/ci-policy: ci / java-core-2-head (pull_request) Skipped
QRun-IO/ci-policy: ci / java-docker-3 (pull_request) Skipped
QRun-IO/ci-policy: ci / java-docker-3-head (pull_request) Skipped
QRun-IO/ci-policy: ci / java-docker-4 (pull_request) Skipped
QRun-IO/ci-policy: ci / java-frontend-browser-5 (pull_request) Skipped
QRun-IO/ci-policy: ci / java-maven-6 (pull_request) Skipped
QRun-IO/ci-policy: ci / java-maven-6-head (pull_request) Skipped
QRun-IO/ci-policy: ci / java-maven-7 (pull_request) Skipped
QRun-IO/ci-policy: ci / java-maven-7-head (pull_request) Skipped
Replace the default-active Core snapshot profile with the released Core
4.1.0-RC.22 BOM, pin qbit-redis to its first release candidate, and replace
the snapshot-era status text with the current 1.0 status.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-05 17:25:50 -06:00
James MaesandGPT-6 Codex 9fbe20c9d6 fix: handle upload recovery metadata and align Core dependency
Verify all 269 Collaboration tests, including PostgreSQL attachment recovery and MySQL/PostgreSQL journals, against the compatible Core snapshot.

Co-Authored-By: GPT-6 Codex <noreply@openai.com>
2026-11-05 17:19:47 -06:00
1c05422901 chore: preserve paused QBit work and document remaining issues
Save the current implementation and README, status, and known-issue documentation at the user-requested stop. No completed release or deployment is claimed.

Co-Authored-By: Claude <noreply@anthropic.com>

Co-Authored-By: GPT-6 Codex <noreply@openai.com>
2026-11-05 17:19:47 -06:00
james.maesandClaude Fable 5.1 0ae1e62b7b fix(presence): never store or publish the session uuid
The session uuid is a bearer credential (clients resume sessions with
it as a cookie or bearer token). The first cut kept it on the lease,
replicated it on the internal presence bus and exposed it through a
public leases() accessor.

Derive an opaque session id instead: "s" + the first 16 hex digits of
HMAC-SHA256(secret, sessionUuid), with QQQ_PRESENCE_SESSION_SECRET
(shared across pods) or a random per-process secret. The raw uuid is
dropped at heartbeat; only the opaque id is stored, replicated and
returned (per-connection viewers and presence.changed leases). The
leases() accessor and Lease record are removed. Tests assert the raw
uuid never appears in bus messages, snapshots or HTTP responses.

Refs #54

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-11-01 16:35:11 -06:00
james.maesandClaude Fable 5.1 47cbc7c72d feat(presence): per-connection viewers and connection counts
Two terminals or tabs of one user collapsed into a single viewer, so
clients could not tell "Admin, twice" from "Admin". The registry
already kept one lease per connection; expose it additively:

- merged viewers carry connections (live leases behind the viewer)
- snapshots and presence.changed carry leaseCount
- GET /presence?perConnection=true adds leases, one viewer per lease
  with an opaque connection id, mode, field and lease start;
  presence.changed always carries leases (subscribers cannot opt in)
- leases record the server-side session uuid, never sent to clients
- counts() still counts users; connectionCounts() counts leases and
  the Who's here card shows both

Extension collaboration 1.2.0; regenerated committed document.

Fixes #54

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-11-01 16:31:37 -06:00
james.maesandClaude Opus 5.5 41bbf2c428 chore: target QQQ 4.1.0-RC.15 (UI API 1.6.0)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 12:27:04 -05:00
james.maesandClaude Opus 5.5 2f6be765f2 feat(ui-api): extension for QQQ UI API 1.6.0 (operationIds, BasicErrorResponseV1, QQQ 4.1.0-RC.14)
Regenerated against UI API 1.6.0: every operation has an operationId and
the standard error responses (BasicErrorResponseV1: error, code, message,
fieldErrors, traceId); the extension's own error schema is kept but
deprecated; hand-written error bodies go through QJavalinUtils so they carry
code/message/traceId. Extension MINOR bumped.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 11:43:37 -05:00
james.maesandClaude Opus 5.5 3df535453e feat(help): ship the qbit-collaboration help bundle through QQQ help bundles, with coverage gate
Host-neutral help (deployment-specific facts removed), registered with
HelpBundles, gated by HelpBundleAssertions. QQQ 4.1.0-RC.7.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 20:27:03 -05:00
james.maesandClaude Opus 5.5 58c87b0378 fix: load feature settings in one transaction, correct scope wording, count only eligible tables
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 17:39:52 -05:00
james.maesandClaude Opus 5.5 3d2a1ded72 feat: Create rows from configuration, Setup card and table help so Feature Settings is never a mystery
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 17:08:52 -05:00
james.maesandClaude Opus 5.5 e014c00428 feat: QQQ 4.1.0-RC.7: record followers provider and secured-data label rules
CollaborationFollowersProvider implements core RecordFollowersProviderInterface
over collaboration_follow (CHANGE/ALERT -> notifyOnChange, COMMENT ->
notifyOnComment, muted excluded), registered via RecordFeaturesMetaData, so
qbit-alerts can notify followers. Cached favorite/recent labels are stored
only when FieldAccessHelper.isRecordLabelFullAccess holds; notification
titles fall back to the table label and id for recipients without FULL
label access. Timeline masking (MASKED shows the mask, HIDDEN omitted,
canary never leaks) is covered by tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 16:29:09 -05:00
james.maesandClaude Opus 5.5 d5adcec567 refactor(email): use qbit-email's public api package; no G1 allow-list
Moves the optional email integration from qbit-email internals to
com.kingsrook.qbits.email.api (qbit-email 0.1.0-RC.2) with identical
behaviour, and moves to qbit-build-parent 2.1.1, whose default G1
allow-lists include qbit-email's API (QRun-IO/qbit-bom#12), so the
per-repo allow-lists are gone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 10:20:32 -05:00
james.maesandClaude Opus 5.5 23d3365437 Merge develop into feature/email-qbit
Keeps develop's changes and re-applies the optional qbit-email 0.1.0-RC.1
delivery on top (adapted to develop's refactors; guardrail allow-lists
for the optional integration where the build parent enforces them).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 08:19:03 -05:00
james.maesandClaude Opus 5.5 ef2ee45b5a feat: demo server picks the user per browser session and sends the real name
A ?user= request parameter (remembered in the collab_dev_user cookie) chooses the
demo identity for that browser, falling back to -Dcollab.dev.user. The session
now carries values.user (name and email) so the frontend shows Alice Morgan
instead of Anonymous. README documents opening a second browser to see presence.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 23:27:08 -05:00
james.maesandClaude Opus 5.5 68fe96c22f feat: rebuild the Collaboration home from standard widgets
Replace the HTML wall of text with a KPI block (comments this week, open
threads, open and overdue tasks, open access requests, attachments with a
human-readable size, active custom fields) and full-width Tags, Custom fields
and Who's here tables, each with a real empty state and no hard-coded colors.
Counts still use the caller's session. Tests updated to assert widget data.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 23:14:27 -05:00
james.maesandClaude Opus 5.5 c9954efef4 feat(email): email mentions, shares and task notices through qbit-email
Phase (d) of QRun-IO/qbit-email docs/DESIGN.md section 11. qbit-email is an
optional dependency (0.1.0-SNAPSHOT until its first RC) used through one
adapter class behind a classpath and instance guard; without it the
existing behaviour is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 23:12:39 -05:00
james.maes 95506ed706 Merge branch 'feature/presence-custom-fields' into feature/demo-dev-server 2026-10-13 22:19:51 -05:00
james.maes bc992fd5f8 Merge branch 'feature/ui-api-endpoints' into feature/presence-custom-fields
# Conflicts:
#	src/main/java/com/kingsrook/qbits/collaboration/model/CollaborationTables.java
2026-10-13 22:19:42 -05:00
james.maes 5f56bf2853 Merge remote-tracking branch 'origin/develop' into feature/ui-api-endpoints 2026-10-13 22:19:14 -05:00
james.maesandClaude Opus 5.5 7b7c921079 test: collaboration demo dev server with seeded Sales data, plus a SELECT custom-field refresh fix
CollaborationDevServer serves the Next dashboard over an in-memory
instance (people, orders, every record feature on, seeded comments,
files, tags, custom fields, tasks, shares, audit history) with mock users
alice, bob and admin. CustomFieldsProvider now registers generated SELECT
possible value sources on refresh.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 22:04:03 -05:00
james.maesandClaude Opus 5.5 08498dd1db feat: custom field designer (JSONB + EAV fallback, managed indexes) and presence
collaboration_field_definition (with DataClassification) and
collaboration_field_value; CustomFieldsProvider contributes ACTIVE fields
through the runtime overlay with JsonPathStorage (Postgres, memory) or a
read-only EAV virtual field elsewhere; Publish/Archive/Rebuild index
actions; the collaborationBuildFieldIndexes job creates expression
indexes CONCURRENTLY (or records the DDL when unmanaged). Presence:
PresenceRegistry replicated over the realtime bus with a 45 s TTL and a
cap, presence.changed events, and POST/DELETE/GET /presence endpoints;
an admin Who's here widget.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 21:09:49 -05:00
james.maesandClaude Opus 5.5 77d005efd3 feat: adopt core collaboration contracts; sharing, tasks, assignment and My work endpoints
Feature settings drive core RecordFeaturesMetaData through
RecordFeatureOverrideProviderInterface; feature permissions come from core
(policy-editor catalog); extension tables declare RecordReferenceTableMetaData
so core enforces parent read access, write rules and mirrored locks; core
cleanup, record-access and summary SPIs are implemented; tags become the
collaborationTags virtual field with a QSubQuery criteria expander (filter,
quick search, #tag) contributed through the runtime overlay; qbit events
publish on the realtime bus. Removes the stand-ins (OtherUserAccess,
UserSessionSupplier, ParentTableRestriction, TagFilterTranslator). Adds
the link, share, access request, task, assignment and My work endpoints.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 20:32:03 -05:00
james.maesandClaude Opus 5.5 9ba6e41377 feat: contingent possible values for comment parent, feature scope name and comment field anchor
parentCommentId lists only its thread (threadId or id = ${input.threadId});
feature settings' scopeName is listed by scopeType (apps or eligible
tables) through FeatureScopeNamePossibleValueProvider; a comment's
fieldName lists the visible fields of its tableName through the reusable
RecordFieldNamePossibleValueProvider. TODOs mark the core dependsOn
switch. One test per pair.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 20:18:24 -05:00
james.maes ab6e8442be Merge remote-tracking branch 'origin/develop' into feature/ui-api-endpoints
# Conflicts:
#	CHANGELOG.md
#	README.md
2026-10-13 20:01:31 -05:00
james.maesandClaude Opus 5.5 22c9ec22fa feat: sharing with access requests, tasks with reminders, owner/assignee and My work
collaboration_share and collaboration_access_request (requesters see only
table and id; non-readers get a notification without record data);
collaboration_task with reminders and overdue notices, Mark done/Reopen;
collaboration_record_assignment with Assign to / Take ownership bulk
actions; MyWorkService summary (open tasks, records assigned, unread
mentions); home cards; parent cleanup.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 18:31:36 -05:00
james.maesandClaude Opus 5.5 be1982a0b1 feat: collaboration UI API extension (/qqq/v1/qbit/collaboration)
31 spec'd operations over favorites, recents, attachments (multipart
upload; download/preview return a short-lived url), tags, comments,
mentions, follow, timeline and people, with Collaboration* typed schemas,
the committed extension fragment openapi/qqq-v1/collaboration.yaml and a
contract test. Built against QQQ 4.1.0-SNAPSHOT for the extension point
(QRun-IO/qqq#1128); moves to 4.1.0-RC.6 when released.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 17:28:53 -05:00
james.maesandClaude Opus 5.5 696f4f48ce feat: tags with per-table vocabularies, approval modes and bulk tag actions
collaboration_tag and collaboration_record_tag; FREE or APPROVED_ONLY per
table from feature settings; normalized names, suggestions, usage counts;
Approve, Merge and Delete tags record actions; Add tags / Remove tags bulk
actions for configured host tables; TagFilterTranslator for the filter
operators, to be wrapped in core's criteria expander once QRun-IO/qqq#1140
is released; tag activity on the timeline; the home Tags card.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 17:03:30 -05:00
james.maesandClaude Opus 5.5 711baede51 feat: comments with mentions, follow/watch and the record activity timeline
collaboration_comment (+ revisions, mentions), collaboration_follow,
collaboration_activity and collaboration_follow_digest tables; comment
threads with markdown bodies, @mentions checked for the recipient's
access, edit history, soft delete and resolve; follow with defaults,
bulk Follow/Unfollow actions and batched change notifications; a
timeline merging audit and activity; a people directory. Notifications go
through a CollaborationNotifier (no-op by default) until the
QAlerts.notify adapter (QRun-IO/qqq#1125) is available.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 16:42:26 -05:00
james.maesandClaude Opus 5.5 0ca89a385b feat: record attachments stored through qbit-object-storage
collaboration_attachment rows per record, uploads streamed into the
configured bucket with size limits and sha256, presigned downloads and
FILE_PREVIEW previews, a streamed-ETL Delete attachments action, parent
cleanup, the home card, and a parent-access stand-in for core's
record-reference security (QRun-IO/qqq#1138) to be replaced when released.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 16:13:18 -05:00
james.maesandClaude Opus 5.5 2f3dcdafd4 feat: favorites and recently viewed, with per-user locks and visibility re-checks
collaboration_favorite and collaboration_recent tables locked to their
owner (admin all-access), FavoritesService (star, unstar, list with label
refresh and Unavailable entries, reorder) and RecentsService (throttled
view recording, list, hidden daily trim). Home shows real counts.
UI API endpoints follow once QRun-IO/qqq#1128 is released.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 15:52:00 -05:00
james.maesandClaude Opus 5.5 0b8a7427da chore: bring the repo to the qbit standard; feature settings and people tables
Scaffold per QRun-IO/qqq docs/QRUN-QBIT-REPO-STANDARD.md (CircleCI orb
0.6.8 workflows, release-rc caller, dependabot, wrapper, checkstyle,
community pointer files). First qbit code: CollaborationQBitProducer,
collaboration_feature_setting and collaboration_user tables, the
Collaboration app home with real counts, and the Postgres DDL script.
Design: QRun-IO/qqq#1136.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 15:09:34 -05:00
james.maes a15067ab03 Initial commit 2026-10-13 14:50:03 -05:00