Implements Maestro task b586a2f1-1532-4194-a19a-8f8386d22590 (Feature 16 - NestQuest API Service).
Done-condition: admin routes for quest definitions — create (title + validated recurrence rule + assignees + windows), update (metadata, rule and/or windows), and set_active (deactivate/reactivate, never hard-delete). Each route validates input and calls the core quest_definitions business layer with no business logic in the handler.
POST /api/v1/admin/quest-definitions: title, rule (built into a ScheduleRule via the recurrence model's own from_dict — no rule validation re-implemented), assignee_child_ids, windows (names or [window, due_time] pairs), optional description/icon.
PATCH /api/v1/admin/quest-definitions/{id}: only supplied fields forwarded (exclude_unset); a supplied windows list replaces the whole set; assignment stays unsettable; explicit null description/icon clears, null rule/windows is rejected.
PATCH /api/v1/admin/quest-definitions/{id}/active: is_active bool straight to the core — the only removal path.
Error mapping is narrow and documented in api/routes_admin.py: the core's definition_id:-prefixed not-exist error maps to 404; every other ValueError (including RuleValidationError) maps to 422, never 500, and unexpected errors are not swallowed as 4xx.
Tests (tests/test_api_admin_questdef.py, shared admin JWT harness) prove against the app's core copy/DB: create persists the definition with its assignees and windows; update persists changes and leaves omitted fields untouched; set_active toggles the flag with the definition still existing (row, rule, assignees, windows intact); non-admin JWT is 403 and absent credential is 401.
Checks: TZ=UTC uv run pytest -q → 1699 passed (1669 baseline + 30 new); new file alone → 30 passed.
Implements Maestro task b586a2f1-1532-4194-a19a-8f8386d22590 (Feature 16 - NestQuest API Service).
Done-condition: admin routes for quest definitions — create (title + validated recurrence rule + assignees + windows), update (metadata, rule and/or windows), and set_active (deactivate/reactivate, never hard-delete). Each route validates input and calls the core quest_definitions business layer with no business logic in the handler.
- POST /api/v1/admin/quest-definitions: title, rule (built into a ScheduleRule via the recurrence model's own from_dict — no rule validation re-implemented), assignee_child_ids, windows (names or [window, due_time] pairs), optional description/icon.
- PATCH /api/v1/admin/quest-definitions/{id}: only supplied fields forwarded (exclude_unset); a supplied windows list replaces the whole set; assignment stays unsettable; explicit null description/icon clears, null rule/windows is rejected.
- PATCH /api/v1/admin/quest-definitions/{id}/active: is_active bool straight to the core — the only removal path.
Error mapping is narrow and documented in api/routes_admin.py: the core's definition_id:-prefixed not-exist error maps to 404; every other ValueError (including RuleValidationError) maps to 422, never 500, and unexpected errors are not swallowed as 4xx.
Tests (tests/test_api_admin_questdef.py, shared admin JWT harness) prove against the app's core copy/DB: create persists the definition with its assignees and windows; update persists changes and leaves omitted fields untouched; set_active toggles the flag with the definition still existing (row, rule, assignees, windows intact); non-admin JWT is 403 and absent credential is 401.
Checks: TZ=UTC uv run pytest -q → 1699 passed (1669 baseline + 30 new); new file alone → 30 passed.
The admin plane gains quest-definition routes on the existing admin
router, mirroring the children routes' thin-adapter pattern: the body
model carries the shape, the handler builds ONE ScheduleRule from the
request's rule object through the recurrence model's own from_dict
(rule validation stays the model's construction-time job), and every
call goes to ONE nestquest_core.quest_definitions business function —
the title/window/assignee policies, the whole-set window replacement
and the never-hard-delete policy all live in the core, never in a
handler.
- POST /quest-definitions: title + rule + assignees + windows (+
optional description/icon), persisted atomically by the core.
- PATCH /quest-definitions/{id}: only supplied fields are forwarded
(exclude_unset); an explicit null description/icon clears it, a null
rule/windows is rejected; assignment stays unsettable here.
- PATCH /quest-definitions/{id}/active: the only removal path — the
flag flips, the row, rule, assignees and windows survive.
Error mapping stays deliberately narrow: the core's definition_id:-
prefixed not-exist error is 404; every other ValueError (including
RuleValidationError) is 422 with the core's message, so a rejected
rule, window, assignee or title from the BODY never disguises itself
as a missing resource and an unexpected error is never swallowed as a
4xx.
Task: b586a2f1-1532-4194-a19a-8f8386d22590 (Feature 16).
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Implements Maestro task b586a2f1-1532-4194-a19a-8f8386d22590 (Feature 16 - NestQuest API Service).
Done-condition: admin routes for quest definitions — create (title + validated recurrence rule + assignees + windows), update (metadata, rule and/or windows), and set_active (deactivate/reactivate, never hard-delete). Each route validates input and calls the core quest_definitions business layer with no business logic in the handler.
Error mapping is narrow and documented in api/routes_admin.py: the core's definition_id:-prefixed not-exist error maps to 404; every other ValueError (including RuleValidationError) maps to 422, never 500, and unexpected errors are not swallowed as 4xx.
Tests (tests/test_api_admin_questdef.py, shared admin JWT harness) prove against the app's core copy/DB: create persists the definition with its assignees and windows; update persists changes and leaves omitted fields untouched; set_active toggles the flag with the definition still existing (row, rule, assignees, windows intact); non-admin JWT is 403 and absent credential is 401.
Checks: TZ=UTC uv run pytest -q → 1699 passed (1669 baseline + 30 new); new file alone → 30 passed.
The admin plane gains quest-definition routes on the existing admin router, mirroring the children routes' thin-adapter pattern: the body model carries the shape, the handler builds ONE ScheduleRule from the request's rule object through the recurrence model's own from_dict (rule validation stays the model's construction-time job), and every call goes to ONE nestquest_core.quest_definitions business function — the title/window/assignee policies, the whole-set window replacement and the never-hard-delete policy all live in the core, never in a handler. - POST /quest-definitions: title + rule + assignees + windows (+ optional description/icon), persisted atomically by the core. - PATCH /quest-definitions/{id}: only supplied fields are forwarded (exclude_unset); an explicit null description/icon clears it, a null rule/windows is rejected; assignment stays unsettable here. - PATCH /quest-definitions/{id}/active: the only removal path — the flag flips, the row, rule, assignees and windows survive. Error mapping stays deliberately narrow: the core's definition_id:- prefixed not-exist error is 404; every other ValueError (including RuleValidationError) is 422 with the core's message, so a rejected rule, window, assignee or title from the BODY never disguises itself as a missing resource and an unexpected error is never swallowed as a 4xx. Task: b586a2f1-1532-4194-a19a-8f8386d22590 (Feature 16).Independent Claude Sonnet 5 review completed for this exact commit.