Changelog

What’s new

A quarter of shipping — Jun 22 – Sep 20, 2026. Compiled from engine, MCP, and indexer release history. Newest first.

Quarter at a glance

Bulk create, read, update, delete and upsert

Send a JSON array to any collection endpoint for bulk write (up to 100 items), or ?id=a,b,c for bulk read. Runs on its own Lambda so a large batch job can't starve regular traffic; each item gets its own success/failure result.

Custom Endpoints

Attach a Function to a URL beyond ordinary CRUD, e.g. POST /orders/summary. Supports public (unauthenticated) routes, synchronous or asynchronous execution, and optional request validation for body and query parameters.

Refresh tokens, and a 1-hour access token to go with them

Access tokens shrank from an unrevocable 7 days to 1 hour. Session longevity now lives in a revocable refresh token (POST /auth/refresh) — a leaked access token expires within the hour instead of staying valid for a week, and a deactivated account loses access within the hour too.

Aaly Functions — customer-authored server-side code

Attach your own Python to an entity's request lifecycle: before or after create/read/update/delete, synchronous or asynchronous, chained in order. One primitive covers validation gates, computed values, webhooks and third-party integrations — no separate feature for each.

File storage — presigned uploads, a files entity, and downloads

Request a presigned URL, upload directly to S3, confirm — then attach files to any entity via an ordinary reference field, with reverse lookup and metadata embedding for free. Downloads are short-lived presigned URLs minted fresh on every read. files is extensible with your own custom fields, same as users.

Major query performance improvements

A bounded date-range filter (e.g. "last 7 days") previously scanned up to 36 months of index buckets; now collapsed into one lookup — roughly 3x faster in production. Paginated collection reads switched to direct batch key lookups instead of a slower partition scan — roughly 2.7x faster. Measured on live traffic: orders GET p50 dropped from ~740ms to under 250ms.

Zero-config MCP connect via OAuth 2.1

claude mcp add --transport http aaly https://mcp.aaly.io/ now works with no manual API key. Sign in through a browser and Claude Code or Cursor connect automatically — self-hosted authorization server with PKCE and Dynamic Client Registration.

Search & filtering, redesigned

Reference fields are now embedded directly on the parent record instead of stored as separate child records. A new asynchronous index table (fed by DynamoDB Streams) backs full query-operator filtering — eq, gt/gte/lt/lte, in/nin, starts — at scale, replacing the old reference-only query path.

September 2026 18 entries

New

Attach download links to a whole file list, not just one record

?presign=true on the files collection endpoint mints a working downloadUrl on every item in the page, opt-in so a plain list call never pays for links nobody asked for.

New

Bulk create, read, update, delete and upsert

Send a JSON array to any collection endpoint for bulk write (up to 100 items), or ?id=a,b,c for bulk read. Runs on its own Lambda so a large batch job can't starve regular traffic; each item gets its own success/failure result.

Fixed

Spec generation for a missing project now returns a clean 404

Previously returned a raw 500.

Security

Auth endpoints no longer echo internal error detail

Stopped leaking raw exception text from authentication failures; also tightened a Custom Endpoint's execution budget to line up with API Gateway's own hard timeout.

New

Atomic $increment / $append on PATCH

PATCH {"stock": {"$increment": -3}} applies directly at the database layer, in one write — no more lost-update races on counters like inventory. min/max bounds are enforced as part of the same write and a violation returns a normal 400 with the value it would have produced.

Fixed

Functions now fire correctly on users and files

A Function or Custom Endpoint attached to either of these built-in entities was silently never invoked. Both now behave like any customer-created entity.

Security

Removed the Functions runAs: "system" privilege escalation

It granted no real authority (no RBAC exists yet to use it) and had a chain-wide footgun — one Function requesting it silently affected every other Function in the same request chain, including ones that never asked.

New

Formula fields — computed values via server-side expressions

Declare a field as round(quantity * unitPrice, 2) or concat(project, '-', name) and it's computed automatically from other fields on the same record, sandboxed, no custom code required. Also generalized automatic unique-key enforcement for entities and fields to be scoped per project/entity instead of per customer.

Fixed

A record could silently vanish from search results forever

A rapid burst of writes to records sharing one filterable value could cause the indexer to drop one record from filtered/faceted results permanently, with the underlying data completely intact. Error responses now also carry a requestId for support correlation.

New

Request & Function execution logs

New GET /requests and GET /function_logs — every API call and every Function invocation is now queryable: status, latency, error text, and captured console output. Answers "was that a bug in my code or the platform's."

New

Custom Endpoints

Attach a Function to a URL beyond ordinary CRUD, e.g. POST /orders/summary. Supports public (unauthenticated) routes, synchronous or asynchronous execution, and optional request validation for body and query parameters.

Improved

Config split into project-wide defaults and per-tenant overrides

platform_variables/platform_secrets set a project's default; variables/secrets override it for one tenant. A Function always sees the merged view, resolved automatically.

Improved

Request tracing across engine ↔ Function calls

Every request and every Function invocation it triggers now shares one requestId, so a full call trace can be reconstructed end to end.

New

Refresh tokens, and a 1-hour access token to go with them

Access tokens shrank from an unrevocable 7 days to 1 hour. Session longevity now lives in a revocable refresh token (POST /auth/refresh) — a leaked access token expires within the hour instead of staying valid for a week, and a deactivated account loses access within the hour too.

Improved

Agent-facing docs split into focused guides

The single platform-capabilities doc served over MCP became per-feature guides — data modeling, querying, auth, files, functions, REST conventions — each with worked request/response examples.

Improved

variables and secrets split into distinct entities

Readable config and encrypted credentials now have contracts suited to each — secrets are never returned by the API and are hard-deleted on revocation, instead of both being one entity behind a boolean flag.

Security

Secret rotation no longer stored the plaintext value

A PATCH that rotated a stored secret (an API key, an OAuth token) was writing the new value to the database unencrypted. Rotation now goes through the same encryption path as creation, and fails closed if it can't verify that.

New

Aaly Functions — customer-authored server-side code

Attach your own Python to an entity's request lifecycle: before or after create/read/update/delete, synchronous or asynchronous, chained in order. One primitive covers validation gates, computed values, webhooks and third-party integrations — no separate feature for each.

August 2026 12 entries

New

MCP upload_file tool

Upload a file to the platform project's own files entity directly from an MCP session — by inline bytes, or by minting a presigned URL for a sandboxed agent to POST to directly.

Fixed

Two file-storage bugs from the first release

Bucket provisioning failed for any customer or project slug containing an underscore; separately, presigned URLs always resolved to the global us-east-1 endpoint instead of the bucket's real region. Both fixed after being caught in live testing.

New

File storage — presigned uploads, a files entity, and downloads

Request a presigned URL, upload directly to S3, confirm — then attach files to any entity via an ordinary reference field, with reverse lookup and metadata embedding for free. Downloads are short-lived presigned URLs minted fresh on every read. files is extensible with your own custom fields, same as users.

Improved

Major query performance improvements

A bounded date-range filter (e.g. "last 7 days") previously scanned up to 36 months of index buckets; now collapsed into one lookup — roughly 3x faster in production. Paginated collection reads switched to direct batch key lookups instead of a slower partition scan — roughly 2.7x faster. Measured on live traffic: orders GET p50 dropped from ~740ms to under 250ms.

Improved

Tenant creation accepts phone or email

Previously required email specifically; now accepts either identifier, matching the flexibility ordinary user signup already had.

Fixed

ChatGPT MCP connector compatibility

ChatGPT's connector rejected a spec-compliant null client_secret for our public, PKCE-only OAuth clients. Worked around with a real, unused placeholder secret purely for interoperability.

New

Zero-config MCP connect via OAuth 2.1

claude mcp add --transport http aaly https://mcp.aaly.io/ now works with no manual API key. Sign in through a browser and Claude Code or Cursor connect automatically — self-hosted authorization server with PKCE and Dynamic Client Registration.

Improved

Tenant creation: password now optional with Google sign-in fallback

Creating a tenant with only an email gives its first user a passwordless account that signs in via Google OAuth.

New

Public signup can now be turned off per project

New projects.publicSignup flag (default off) gates whether anyone can self-register a brand-new tenant; tenants.publicSignup independently gates joining one existing tenant. A project owner can bootstrap their first tenant and user directly via the API even with public signup off.

Security

Removed role/type from the universal users schema

Both were client-settable on every project by default with no gating, and would have collided with a future permissions model. Add your own role field explicitly if you need one.

New

GET /entities / GET /fields now include built-in system schema

Previously only showed your own custom entities and fields. Now also lists entities, fields, tenants and their base fields, each tagged _system: true.

New

Tenants moved to the platform table; users becomes extensible

Tenant records now live on the platform table and are managed platform-admin-only. users is now a hybrid entity — add your own custom fields via POST /fields exactly like any of your own entities, while base fields (email, password…) stay fixed.

July 2026 14 entries

Improved

MCP server migrated to MCP SDK 2.0

Internal upgrade to the current protocol SDK; no change to tool behavior.

Fixed

update_field silently dropping immutable attributes

A PATCH that mixed immutable and mutable field attributes was quietly discarding the immutable ones.

New

Facets now automatic; selective ?facets=

Any searchable field on an eligible type (enum, boolean, list, reference, date) is now automatically faceted — distinct-value counts, no separate opt-in flag. ?facets=status,priority lets you fetch just the fields you need.

Fixed

Boolean and number field defaults were stored as strings

A record relying on a field's schema default (rather than an explicit value) returned "true"/"false" instead of a real boolean, silently breaking search:true filtering on that field.

New

Search & filtering, redesigned

Reference fields are now embedded directly on the parent record instead of stored as separate child records. A new asynchronous index table (fed by DynamoDB Streams) backs full query-operator filtering — eq, gt/gte/lt/lte, in/nin, starts — at scale, replacing the old reference-only query path.

Fixed

PATCH reliability: unique constraints and schema cache

Unique-value reservation records and the schema cache are now correctly reconciled on PATCH; empty PATCH transactions are guarded against.

Improved

Deletion protection and point-in-time recovery on every table

Enabled by default at table creation for both platform and project DynamoDB tables.

New

MCP API keys can carry a default project

A key minted with context: {"projectId": "PRJn"} pre-scopes MCP tool calls to that project, so an agent never has to pick or type a project id.

Improved

Slug and naming rules adjusted

Two different organizations can now share a display name. Hyphens are disallowed in customer/project slugs, since they feed directly into DynamoDB table names.

Fixed

multiTenant signup gating now enforced correctly

Also: list fields now require a declared valueType (string/number/boolean/object).

New

MCP prompts and a project capability overview

Added multi-step recipe prompts and describe_project — a one-shot summary of a project's tenant model, entities, relationships and filterable fields.

Improved

Structured request/response logging with client-type tagging

Every request now produces a paired entry/exit log line with duration, status, and whether the caller was a browser, MCP, or another client — a debugging aid, not an access-control signal.

New

System fields renamed with a _ prefix

id, status, createdAt and friends became _status, _createdAt, etc. You can now safely name your own fields status, type, or createdAt with zero collision risk.

Improved

Hosted MCP server moved to a custom domain

https://mcp.aaly.io/ is now the endpoint directly — no /mcp path segment.

June 2026 2 entries

Security

Reject requests where the URL doesn't match the caller's own project

A token for one customer/project could previously be presented against another project's URL slugs.

Improved

Platform renamed to aaly / platform

The reserved admin customer/project slugs moved from thunderbase/admin to aaly/platform.

← Back to home