Docyrus API Doctor
Post-implementation checklist for Docyrus API code. Run through each applicable check after writing or modifying API logic. Fix every issue found before considering the task complete.
How to use: After implementing API logic, scan the changed code against each check below. Skip checks that don't apply to the code at hand. For detailed explanations and fix examples, read references/checklist-details.md.
BUG — Will Cause Errors
| # | Check | What to look for |
|---|
| B1 | Missing columns parameter | Any .list() or .get() call without a columns property. Without it, only id is returned. |
| B2 | limit: 0 in query payload | limit set to 0 causes an API error. Remove limit entirely or set a positive integer. |
| B3 | Child query key not in columns | If childQueries defines key orders, the string orders must also appear in columns. |
| B4 | Formula key not in columns | If formulas defines key total, the string total must also appear in columns. |
| B5 | Aggregation via @ column syntax | Using count@field or sum@field in columns. Use the calculations parameter instead. |
| B6 | distinctColumns with calculations | These are mutually exclusive. Use calculations for aggregation. |
| B7 | Formula extract input count | extract blocks must have exactly 1 input. |
| B8 | Formula not operand count | not blocks must have exactly 1 operand. |
| B9 | Formula and/or operand count | and/or blocks must have at least 2 operands. |
| B10 | Formula math operand count | Math operations (+, -, *, /, %) must have at least 2 operands. |
| B11 | Formula case without when | case expressions must have at least 1 when clause. |
| B12 | Uncast literal in jsonb_build_object | String literals inside jsonb_build_object need explicit "cast": "text" — auto-cast only works inside concat/concat_ws. |
PERFORMANCE — Degrades Speed or Wastes Resources
| # | Check | What to look for |
|---|
| P1 | Unnecessary limit on aggregation queries | When using calculations without needing raw rows, don't send limit. Aggregation returns a single grouped result naturally. |
| P2 | fullCount just to get a total count | If you only need the count (not the rows), use calculations: [{ func: 'count', field: 'id', name: 'total' }] instead of fullCount: true with row fetching. |
| P3 | Unnecessary columns on calculation-only queries | When using calculations and only reading aggregated values, don't send columns. The calculation result is returned without needing column selection. |
| P4 | Over-fetching columns | Columns selected in columns but never read in the consuming code. Only select what you render or process. |
| P5 | Large limit without pagination | limit > 200 without offset/fullCount pagination risks slow responses and high memory usage. |
| P6 | Missing expand causing N+1 | Rendering relation/enum/user field .name but not including that field in expand. Without expand, you get only the ID. |
| P7 | Fetching rows for existence checks | Fetching records just to check if any exist. Use calculations count instead. |
| P8 | Redundant overlapping queries | Multiple queries on the same data source fetching overlapping columns that could be combined into one. |
CODE QUALITY — Causes Maintenance Pain
| # | Check | What to look for |
|---|
| Q1 | Heavy as type assertions on responses | Casting API responses with as Array<...> without runtime validation. Prefer typed collection return types or add validation. |
| Q2 | Missing enabled on dependent queries | useQuery that depends on a runtime value (e.g., recordId) but lacks enabled: !!recordId. The query fires with undefined. |
| Q3 | No error handling on mutations | .create(), .update(), .delete() calls without try/catch or error feedback to the user. |
| Q4 | Missing query invalidation after mutations | After create/update/delete, related query keys must be invalidated so lists refresh. |
| Q5 | Serial cache invalidations | Multiple await queryClient.invalidateQueries(...) in sequence. Use Promise.all() for independent invalidations. |
| Q6 | Using deprecated expandTypes | Replace with the expand parameter. |
| Q7 | Hardcoded data source paths | Raw client.get('/v1/apps/base/data-sources/project/items') instead of using generated collection hooks. |
| Q8 | distinctColumns without orderBy | distinctColumns requires orderBy to define which row wins per group. |
How to Run
- Identify all files changed in this task that contain Docyrus API calls
- For each file, scan for
.list(, .get(, .create(, .update(, .delete(, client.get(, client.post(, client.patch(, client.delete(
- Check each call site against the BUG checks (B1-B12)
- Check query payloads against PERFORMANCE checks (P1-P8)
- Check surrounding code (hooks, error handling, invalidation) against CODE QUALITY checks (Q1-Q8)
- Fix all issues found, starting with BUG category
References
references/checklist-details.md — Detailed explanation, detection pattern, and before/after fix example for every check item