16 KiB
| phase | plan | type | wave | depends_on | files_modified | autonomous | requirements | must_haves | |||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 24-aws-route-53-dns-sync-track-changes-crud-operations-full-aud | 06 | execute | 3 |
|
|
true |
|
|
Purpose: SC-1 (sync runs on a schedule) and SC-6 (integration appears in the existing sync
admin UI/scheduler alongside the others).
Output: modified lib/services/sync-scheduler.ts and app/admin/sync/page.tsx, plus a
public/logos/route53.svg tile asset.
<execution_context> @$HOME/.claude/get-shit-done/workflows/execute-plan.md @$HOME/.claude/get-shit-done/templates/summary.md </execution_context>
@.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/phases/24-aws-route-53-dns-sync-track-changes-crud-operations-full-aud/24-PATTERNS.md @.planning/phases/24-aws-route-53-dns-sync-track-changes-crud-operations-full-aud/24-CONTEXT.md @.planning/phases/24-aws-route-53-dns-sync-track-changes-crud-operations-full-aud/24-02-SUMMARY.mdlib/services/sync-scheduler.ts: line 25: sync_type: 'incremental' | 'full' | 'veeam-incremental' | ... | 'phishing-sweep'; line 147: sync_schedules table DDL — sync_type VARCHAR(30) NOT NULL (no CHECK constraint; 'route53-incremental' is 19 chars and fits) line 180: const defaultSchedules = [ ... ] // entries: { id, name, description, cron_expression, sync_type, is_enabled } line 312: for (const schedule of defaultSchedules) { INSERT INTO sync_schedules ... ON CONFLICT DO NOTHING } line 413+: dispatch chain — if (config.sync_type === 'veeam-incremental') { ... } else if (...) line 478-493: pax8-daily branch — the ONE branch that also checks integration_settings.disabled. Route 53 must NOT copy that gate (D-10). line 494-504: mimecast-sync branch — config-check-only pattern; this is the shape to copy.
app/admin/sync/page.tsx: lines 9-16: interface IntegrationCard { id, category, product, description, href, logo, color } lines 20-29: const INTEGRATIONS: IntegrationCard[] = [ ... 'pax8' entry is last ] lines 32-39: COLOR_MAP — available keys: red, green, blue, orange, purple, gray (no others) line 266: const colors = COLOR_MAP[intg.color]; // an unmapped color yields undefined
lib/services/route53-sync-service.ts: getRoute53SyncService(): Route53SyncService #fullSync(triggeredBy?): Promise #incrementalSync(triggeredBy?): Promise
lib/services/route53-factory.ts: isRoute53Configured(): boolean
Task 1: Add route53 sync types, schedules, and dispatch branches to the scheduler lib/services/sync-scheduler.ts - lib/services/sync-scheduler.ts (read the full file — the sync_type union at line 25, the sync_schedules DDL at line 147, defaultSchedules at lines 180-311, the seed loop at line 312, and the whole dispatch chain from line 413 onward) - lib/services/route53-sync-service.ts (getRoute53SyncService — plan 24-02) - lib/services/route53-factory.ts (isRoute53Configured — plan 24-01) - .planning/phases/24-aws-route-53-dns-sync-track-changes-crud-operations-full-aud/24-PATTERNS.md (sync-scheduler section — the exact branch shape, and the explicit instruction NOT to copy PAX8's disable gate) - .planning/phases/24-aws-route-53-dns-sync-track-changes-crud-operations-full-aud/24-CONTEXT.md (D-10, D-11) Modify `lib/services/sync-scheduler.ts` in three places.-
Line 25
sync_typeunion: append| 'route53-incremental' | 'route53-full'to the existing pipe-delimited string union. Do not reformat the rest of the line. -
defaultSchedulesarray (starts line 180): append two entries matching the exact object shape of the surroundingveeam-incremental/veeam-fullentries at lines 198-221:- id
route53-incremental, nameRoute 53 Incremental Sync, descriptionSyncs AWS Route 53 hosted zones and records every 15 minutes, cron_expression*/15 * * * *, sync_typeroute53-incremental, is_enabledfalse. - id
route53-full, nameRoute 53 Full Sync, descriptionFull AWS Route 53 zone and record reconciliation daily at 4:00 AM, cron_expression0 4 * * *, sync_typeroute53-full, is_enabledfalse.is_enabled: falsematches every newly-introduced integration in this file — an operator enables them from/adminafter confirming credentials. The0 4 * * *slot avoids the known collisions at 2:00 AM (veeam-full,qbo-sync-2am,mimecast-sync) and 3:00 AM (weekly-full's0 3 * * 0). Enumerate everycron_expressionin the live array before committing and pick the next free hour if 4:00 AM is now occupied. The seed loop at line 312 usesON CONFLICT DO NOTHING, so existing deployments pick these up without overwriting operator-modified rows.
- id
-
Dispatch chain (line 413 onward): add two
else ifbranches following themimecast-syncconfig-check-only shape at lines 494-504, NOT thepax8-dailyshape at lines 478-493:else if (config.sync_type === 'route53-incremental')— dynamicallyawait import('@/lib/services/route53-factory')forisRoute53Configured; if false, log[SCHEDULER] Skipping route53-incremental — Route 53 not configuredand return; otherwise dynamicallyawait import('@/lib/services/route53-sync-service')and callgetRoute53SyncService().incrementalSync('scheduled').else if (config.sync_type === 'route53-full')— same shape, callingfullSync('scheduled'). Use dynamicimport()in both branches (as every other branch does) so the sync service module is not eager-loaded at scheduler-import time. The scheduler self-initializes as a side effect of its first server-side import, and a top-level import here would pull the AWS SDK into every server module graph.
CRITICAL (D-10): do NOT add an integration_settings.disabled query to either branch. PAX8
is the codebase's sole exception where disabling also blocks sync; CONTEXT.md D-10 states
Route 53 explicitly does not join that list. Add a short comment above the first Route 53
branch recording this, so a future reader does not "fix" the apparent inconsistency with the
PAX8 branch sitting a few lines above.
Confirm sync_schedules.sync_type at line 147 is VARCHAR(30) with no CHECK constraint
before relying on the new values fitting — route53-incremental is 19 characters.
npx tsc --noEmit --pretty && test $(grep -c "route53-incremental" lib/services/sync-scheduler.ts) -ge 3 && test $(grep -c "route53-full" lib/services/sync-scheduler.ts) -ge 3 && test $(grep -A12 "config.sync_type === 'route53" lib/services/sync-scheduler.ts | grep -c integration_settings) -eq 0 && echo PASS
<acceptance_criteria>
- route53-incremental and route53-full each appear at least 3 times in lib/services/sync-scheduler.ts (union, defaultSchedules, dispatch)
- Both new defaultSchedules entries have is_enabled: false
- Neither Route 53 dispatch branch body contains integration_settings (D-10) — grep over the 12 lines following each branch head returns 0
- Both dispatch branches use dynamic await import(...); no top-level route53 import exists: grep -c "^import.*route53" lib/services/sync-scheduler.ts returns 0
- The route53-full cron hour differs from every other daily cron_expression hour in defaultSchedules — verified by enumerating the array
- A comment above the Route 53 branches records why the PAX8 disable gate is deliberately absent
- npx tsc --noEmit --pretty exits 0
</acceptance_criteria>
Scheduler knows both Route 53 sync types, seeds them disabled, dispatches via dynamic import, and never consults the disable toggle.