Skip to content

Add schedules API endpoints#11331

Merged
abnegate merged 18 commits into1.8.xfrom
feat-schedules-endpoints
Feb 18, 2026
Merged

Add schedules API endpoints#11331
abnegate merged 18 commits into1.8.xfrom
feat-schedules-endpoints

Conversation

@premtsd-code
Copy link
Copy Markdown
Contributor

@premtsd-code premtsd-code commented Feb 15, 2026

Summary

  • Adds REST API endpoints for schedules under the projects group: Create (POST /v1/projects/:projectId/schedules), Get (GET /v1/projects/:projectId/schedules/:scheduleId), and List (GET /v1/projects/:projectId/schedules)
  • Auth: AuthType::ADMIN (console session), consistent with keys and platforms endpoints
  • Adds schedules.read and schedules.write scopes, event configuration, and Response model

Test plan

  • composer lint passes
  • composer format passes
  • Added E2E tests
  • CI pipeline passes

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Feb 15, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This pull request introduces a complete schedules management feature for projects. The changes include new configuration entries for events, permissions, and scopes; a Schedule response model with associated validators; three new HTTP endpoints for creating, retrieving, and listing schedules; and comprehensive end-to-end tests covering creation, retrieval, listing, and project isolation scenarios. The feature integrates with existing database and event systems.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 27.12% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The pull request title 'Add schedules API endpoints' directly and clearly summarizes the primary change—introducing REST API endpoints for schedules management.
Description check ✅ Passed The description is well-related to the changeset, detailing the endpoints added, authentication approach, new scopes, test coverage, and verification steps performed.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat-schedules-endpoints

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown

github-actions bot commented Feb 15, 2026

Security Scan Results for PR

Docker Image Scan Results

Package Version Vulnerability Severity
libecpg 18.1-r0 CVE-2026-2004 HIGH
libecpg 18.1-r0 CVE-2026-2005 HIGH
libecpg 18.1-r0 CVE-2026-2006 HIGH
libecpg 18.1-r0 CVE-2026-2007 HIGH
libecpg-dev 18.1-r0 CVE-2026-2004 HIGH
libecpg-dev 18.1-r0 CVE-2026-2005 HIGH
libecpg-dev 18.1-r0 CVE-2026-2006 HIGH
libecpg-dev 18.1-r0 CVE-2026-2007 HIGH
libpq 18.1-r0 CVE-2026-2004 HIGH
libpq 18.1-r0 CVE-2026-2005 HIGH
libpq 18.1-r0 CVE-2026-2006 HIGH
libpq 18.1-r0 CVE-2026-2007 HIGH
libpq-dev 18.1-r0 CVE-2026-2004 HIGH
libpq-dev 18.1-r0 CVE-2026-2005 HIGH
libpq-dev 18.1-r0 CVE-2026-2006 HIGH
libpq-dev 18.1-r0 CVE-2026-2007 HIGH
postgresql18-dev 18.1-r0 CVE-2026-2004 HIGH
postgresql18-dev 18.1-r0 CVE-2026-2005 HIGH
postgresql18-dev 18.1-r0 CVE-2026-2006 HIGH
postgresql18-dev 18.1-r0 CVE-2026-2007 HIGH

Source Code Scan Results

🎉 No vulnerabilities found!

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/Appwrite/Platform/Modules/Schedules/Http/Schedules/Create.php`:
- Around line 93-108: In Create.php inside the schedule creation block (the try
that calls $authorization->skip -> $dbForPlatform->createDocument), replace
setting 'resourceUpdatedAt' => DateTime::now() with the actual resource
last-updated timestamp from the referenced resource (use
$resource->getAttribute('$updatedAt') so the Schedule reflects when the resource
was last updated); ensure the value you pass matches the expected DateTime
type/format used by the Schedule model and handle any nulls or missing attribute
appropriately before creating the Document.
🧹 Nitpick comments (4)
src/Appwrite/Platform/Modules/Schedules/Http/Schedules/Create.php (1)

106-108: DuplicateException catch swallows the root cause with a generic message.

Since schedules use auto-generated IDs, a DuplicateException here would indicate an unexpected collision. Logging the underlying exception or including a more specific error code would aid debugging.

tests/e2e/Services/Schedules/SchedulesCustomServerTest.php (3)

89-98: Test relies on validation ordering — consider using a valid resource ID.

This test sends an invalid cron with a non-existent resourceId. If the API validates the cron expression first, the 400 assertion holds. But if resource lookup is evaluated before cron validation in a future refactor, this test would break with a 404. Consider either:

  • Using the functionId from a @depends on testCreateSchedule, or
  • Adding resourceType => 'invalid' so that input validation is unambiguously triggered first.

This is minor since it works today, but it makes the test less resilient to implementation changes.


153-179: $data parameter is unused — consider using it to strengthen the test.

Static analysis flags $data as unused. Since @depends testCreateSchedule provides the scheduleId, you could use it to assert the created schedule actually appears in the listing, making this test more meaningful than just checking structure.

♻️ Suggested improvement
     public function testListSchedules(array $data): void
     {
+        $scheduleId = $data['scheduleId'];
+
         /**
          * Test for SUCCESS
          */
         $response = $this->listSchedules();
 
         $this->assertEquals(200, $response['headers']['status-code']);
         $this->assertIsArray($response['body']['schedules']);
         $this->assertGreaterThanOrEqual(1, $response['body']['total']);
         $this->assertGreaterThanOrEqual(1, \count($response['body']['schedules']));
 
+        // Verify the created schedule appears in the listing
+        $scheduleIds = array_column($response['body']['schedules'], '$id');
+        $this->assertContains($scheduleId, $scheduleIds);
+
         // Verify schedule structure
         $schedule = $response['body']['schedules'][0];

181-208: $data parameter is unused — same issue as testListSchedules.

Same recommendation as above: either use $data to verify the specific schedule appears in filtered results (strengthening the test), or document that @depends is purely for ordering.

@github-actions
Copy link
Copy Markdown

github-actions bot commented Feb 15, 2026

✨ Benchmark results

  • Requests per second: 1,862
  • Requests with 200 status code: 335,242
  • P99 latency: 0.086971806

⚡ Benchmark Comparison

Metric This PR Latest version
RPS 1,862 1,147
200 335,242 206,648
P99 0.086971806 0.19635298

@premtsd-code premtsd-code force-pushed the feat-schedules-endpoints branch from 638b173 to 5ee1a45 Compare February 15, 2026 22:49
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@tests/e2e/Services/Schedules/SchedulesCustomServerTest.php`:
- Around line 13-17: In SchedulesCustomServerTest, replace the incorrect trait
usage of SideClient with SideServer so the class declaration uses "use
SideServer;" alongside SchedulesBase and ProjectConsole; update any imports or
trait references if necessary to match the other *CustomServerTest classes and
ensure test authentication uses the server-side trait (verify methods provided
by SideServer are used in the class instead of SideClient).
🧹 Nitpick comments (1)
src/Appwrite/Platform/Modules/Schedules/Http/Schedules/XList.php (1)

87-103: Cursor document is not validated for project ownership.

The cursor schedule is fetched without checking if it belongs to the requested project (line 94-96). While the projectId filter in the query set means results won't leak data from other projects, a cursor pointing to a schedule in a different project could cause unexpected empty results or confusing pagination behavior. Consider validating $cursorDocument->getAttribute('projectId') === $project->getId().

Proposed fix
         if ($cursorDocument->isEmpty()) {
             throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "Schedule '{$scheduleId}' for the 'cursor' value not found.");
         }
+
+        if ($cursorDocument->getAttribute('projectId') !== $project->getId()) {
+            throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "Schedule '{$scheduleId}' for the 'cursor' value not found.");
+        }

         $cursor->setValue($cursorDocument);

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
tests/e2e/Services/Schedules/SchedulesConsoleClientTest.php (2)

22-146: Consider adding test coverage for execution and message resource types.

The PR objective mentions resource validation for functions, executions, and messages, but only the function resource type is exercised here. Adding at least one success-path test for execution and message would improve confidence in the validation logic for all three types.


13-17: Missing test coverage for authentication/authorization enforcement.

The PR states that schedules endpoints use AuthType::ADMIN (console session). There are no tests verifying that unauthenticated requests or non-admin API key requests are rejected. Consider adding a test that omits the console session headers and asserts a 401 response to confirm admin-scope enforcement is working correctly.

@premtsd-code premtsd-code force-pushed the feat-schedules-endpoints branch from 43551ca to be9c3e1 Compare February 16, 2026 06:40
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
tests/e2e/Services/Schedules/SchedulesConsoleClientTest.php (1)

151-182: Consider asserting resourceId matches the expected functionId.

The get-schedule success path validates most fields but doesn't verify that resourceId matches $data['functionId']. This would strengthen the assertion that the correct schedule was returned.

Suggested addition
 $this->assertEquals('function', $response['body']['resourceType']);
+$this->assertEquals($data['functionId'], $response['body']['resourceId']);
 $this->assertEquals('0 0 * * *', $response['body']['schedule']);

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@Dockerfile`:
- Around line 17-19: This RUN step adds an external CA without integrity checks;
either revert this unrelated change or make it safe: for the
AAA_Certificate_Services.crt download (the wget line) require a pinned
SHA256/fingerprint and verify the file before running update-ca-certificates,
e.g. download to a temporary file, compute/compare the expected SHA256 or
certificate fingerprint, fail the build if it doesn't match, and only then move
it into /usr/local/share/ca-certificates/ and call update-ca-certificates; if
the cert is not essential for this PR, remove the entire wget +
update-ca-certificates block and submit it in a separate PR with justification.

@premtsd-code premtsd-code force-pushed the feat-schedules-endpoints branch from dcd0555 to 818c786 Compare February 16, 2026 17:43
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
tests/e2e/Services/Schedules/SchedulesBase.php (1)

11-12: Consider renaming helper to avoid PHPUnit auto-discovery.

A test* method in a trait will be picked up as a test in every class using it. If this is intended as a helper, renaming prevents accidental execution.

♻️ Suggested rename
-    public function testCreateProject(): array
+    public function createProject(): array

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Fix all issues with AI agents
Before applying any fix, first verify the finding against the current code and
decide whether a code change is actually needed. If the finding is not valid or
no change is required, do not modify code for that item and briefly explain why
it was skipped.

In `@src/Appwrite/Platform/Modules/Schedules/Http/Schedules/Create.php`:
- Around line 131-144: The code in Create.php currently sets $attributes['data']
= \json_decode($data, true) without checking for decode errors; update the
Create handler to validate the result of \json_decode($data, true) (e.g., check
json_last_error() !== JSON_ERROR_NONE and use json_last_error_msg()) and if
decoding failed return/throw a proper validation/error response (or refuse to
persist) instead of silently assigning null to $attributes['data']; ensure you
reference the $data variable and $attributes array in this fix so any invalid
JSON from users causes a clear error rather than a null schedule data value.
🧹 Nitpick comments (1)
🤖 Fix all nitpicks with AI agents
Before applying any fix, first verify the finding against the current code and
decide whether a code change is actually needed. If the finding is not valid or
no change is required, do not modify code for that item and briefly explain why
it was skipped.

In `@src/Appwrite/Platform/Modules/Schedules/Http/Schedules/Create.php`:
- Around line 131-144: The code in Create.php currently sets $attributes['data']
= \json_decode($data, true) without checking for decode errors; update the
Create handler to validate the result of \json_decode($data, true) (e.g., check
json_last_error() !== JSON_ERROR_NONE and use json_last_error_msg()) and if
decoding failed return/throw a proper validation/error response (or refuse to
persist) instead of silently assigning null to $attributes['data']; ensure you
reference the $data variable and $attributes array in this fix so any invalid
JSON from users causes a clear error rather than a null schedule data value.
src/Appwrite/Platform/Modules/Schedules/Http/Schedules/Create.php (1)

131-144: Missing error handling for json_decode on user-supplied data.

On line 143, \json_decode($data, true) is called without checking the result. While the JSON validator on line 91 should catch syntactically invalid JSON, if for any reason decoding fails, json_decode returns null and the schedule's data attribute would silently be set to null instead of the intended value.

Consider adding a guard:

Proposed fix
         if ($data !== null) {
-            $attributes['data'] = \json_decode($data, true);
+            $decoded = \json_decode($data, true);
+            if ($decoded === null && $data !== 'null') {
+                throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'Invalid JSON data');
+            }
+            $attributes['data'] = $decoded;
         }
🤖 Prompt for AI Agents
Before applying any fix, first verify the finding against the current code and
decide whether a code change is actually needed. If the finding is not valid or
no change is required, do not modify code for that item and briefly explain why
it was skipped.
In `@src/Appwrite/Platform/Modules/Schedules/Http/Schedules/Create.php` around
lines 131 - 144, The code in Create.php currently sets $attributes['data'] =
\json_decode($data, true) without checking for decode errors; update the Create
handler to validate the result of \json_decode($data, true) (e.g., check
json_last_error() !== JSON_ERROR_NONE and use json_last_error_msg()) and if
decoding failed return/throw a proper validation/error response (or refuse to
persist) instead of silently assigning null to $attributes['data']; ensure you
reference the $data variable and $attributes array in this fix so any invalid
JSON from users causes a clear error rather than a null schedule data value.

@premtsd-code premtsd-code force-pushed the feat-schedules-endpoints branch from e9a960f to a9226e9 Compare February 17, 2026 09:16
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src/Appwrite/Platform/Modules/Schedules/Http/Projects/Schedules/Create.php (1)

138-140: json_decode failure not handled.

If json_decode($data, true) fails (e.g., deeply nested JSON exceeding PHP's default depth), it returns null and json_last_error() would indicate an error. The JSON validator on the param likely catches most cases, but a malformed decode would silently set data to null.

This is unlikely to be an issue in practice given the upstream validator, but worth noting.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/Appwrite/Platform/Modules/Schedules/Http/Projects/Schedules/Create.php`
around lines 138 - 140, In Create.php the result of json_decode($data, true) is
not checked so a decode error silently sets $attributes['data'] to null; after
calling json_decode in the Create class/method check json_last_error() (or
json_last_error_msg()) and handle failures by returning or throwing a
validation/400-style error (or keeping the raw string) instead of assigning null
to $attributes['data']; update the logic around the $data handling and
$attributes['data'] assignment so only a successful decode (JSON_ERROR_NONE)
populates the attribute and any decode error produces an explicit error
response.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/Appwrite/Platform/Modules/Schedules/Http/Projects/Schedules/Create.php`:
- Around line 138-140: In Create.php the result of json_decode($data, true) is
not checked so a decode error silently sets $attributes['data'] to null; after
calling json_decode in the Create class/method check json_last_error() (or
json_last_error_msg()) and handle failures by returning or throwing a
validation/400-style error (or keeping the raw string) instead of assigning null
to $attributes['data']; update the logic around the $data handling and
$attributes['data'] assignment so only a successful decode (JSON_ERROR_NONE)
populates the attribute and any decode error produces an explicit error
response.

@premtsd-code premtsd-code force-pushed the feat-schedules-endpoints branch from a9226e9 to 8b78367 Compare February 17, 2026 09:19
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/Appwrite/Utopia/Response/Model/Schedule.php`:
- Around line 43-48: Update the description for the schema rule added in
Schedule.php (the addRule('resourceUpdatedAt', ...) call) to reflect that
resourceUpdatedAt is a scheduler change-tracking timestamp, not the resource's
actual last-updated time; keep the type (self::TYPE_DATETIME), default and
example (self::TYPE_DATETIME_EXAMPLE) unchanged but replace the misleading
description string with something like "Change-tracking timestamp used by the
scheduler to detect resource changes (not the resource's last-updated time)".

@premtsd-code premtsd-code force-pushed the feat-schedules-endpoints branch 3 times, most recently from a78bec5 to 89abd83 Compare February 17, 2026 17:29
@premtsd-code premtsd-code force-pushed the feat-schedules-endpoints branch from 01e54c6 to 63bb69d Compare February 18, 2026 06:23
Copy link
Copy Markdown
Member

@abnegate abnegate left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updte workflow to run new tests

@abnegate abnegate merged commit d118bb2 into 1.8.x Feb 18, 2026
108 checks passed
@abnegate abnegate deleted the feat-schedules-endpoints branch February 18, 2026 08:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants