Replace all instances of `detail=str(e)`, `detail=f"...{exc}"`, and similar
patterns that exposed internal exception messages to HTTP clients in
services/ml/app/main.py. All exception details are now logged server-side
only via logger.error(), while clients receive a generic "Internal server error"
message. Fixes 9 handlers across predict, batch predict, pattern detection,
training start, training runs fetch, training run delete, dataset info,
build dataset, and model load endpoints.
Mark task 5.1 as completed in tasks.md.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
13 KiB
13 KiB
1. Security Critical — Git & Credentials
- 1.1
[haiku]Add.envto.gitignoreand rungit rm --cached .envto untrack it - 1.2
[haiku]Addmodels/and*.pklto.gitignore - 1.3
[haiku]Replace real credentials in.env.examplewith placeholders (POSTGRES_PASSWORD=change_me_to_a_strong_password) - 1.4
[haiku]Remove SQL comment with credentials fromservices/ml/app/db.pyand add fail-fast check for missingDATABASE_URL - 1.5
[sonnet]Updatedocker-compose.ymlto use${POSTGRES_USER},${POSTGRES_PASSWORD},${POSTGRES_DB}env var interpolation in all DATABASE_URL values - 1.6
[haiku]Bind PostgreSQL port to127.0.0.1:5432:5432indocker-compose.yml - 1.7
[haiku]Bind MLflow port to127.0.0.1:5000:5000indocker-compose.yml - 1.8
[haiku]Bind ML service port to127.0.0.1:8001:8001indocker-compose.yml
2. Security Critical — Input Validation & CORS
- 2.1
[haiku]Validaterun_idmatches/^[a-zA-Z0-9_-]+$/insrc/app/api/training/runs/[run_id]/route.tsbefore interpolation - 2.2
[sonnet]Validaterun_idformat and usePath.resolve()+ directory containment check inservices/ml/app/main.py(model load at line 1203, delete at line 1312) - 2.3
[sonnet]Add file size check (reject >10MB) and row count limit (500,000) tosrc/app/api/upload/route.ts - 2.4
[haiku]Add file type validation (.csvextension, text MIME type) tosrc/app/api/upload/route.ts - 2.5
[haiku]Fix CORS inservices/ml/app/main.py: replaceallow_origins=["*"]with["http://localhost:3000"]and supportCORS_ORIGINSenv var
3. Authentication
- 3.1
[sonnet]Createsrc/middleware.tswith API key auth middleware: readAPI_KEYenv var, checkX-API-Keyheader on all/api/*routes except/api/health, return 401 if invalid - 3.2
[sonnet]Add FastAPIDepends()API key dependency inservices/ml/app/main.py: readAPI_KEYenv var, checkX-API-Keyheader, exempt/healthendpoint - 3.3
[sonnet]Update all Next.js proxy routes to forwardX-API-Keyheader to ML service - 3.4
[haiku]AddAPI_KEYto.env.examplewith placeholder value and instructions
4. API Route Hardening (Next.js)
- 4.1
[sonnet]Add Zod schema validation tosrc/app/api/predict/route.ts(validate pair, timeframe, candles array) - 4.2
[sonnet]Add Zod schema validation tosrc/app/api/predict/batch/route.ts(validate pair, timeframe, start_date, end_date) - 4.3
[sonnet]Add Zod schema validation tosrc/app/api/model/load/route.ts(validate run_id) - 4.4
[sonnet]Add Zod schema validation tosrc/app/api/training/start/route.ts(validate model_type) - 4.5
[sonnet]Add Zod schema validation tosrc/app/api/patterns/detect/route.ts(validate candles, patterns array) - 4.6
[sonnet]Replaceerror.messagewith generic"Internal server error"in all catch blocks across 7+ route files:health/route.ts,candles/route.ts,annotations/route.ts,annotations/[id]/route.ts,upload/route.ts,export/route.ts,span-annotations/export/route.ts - 4.7
[sonnet]RequirechartIdfor bulk delete insrc/app/api/annotations/route.ts— reject?all=truewithout chartId with HTTP 400 - 4.8
[sonnet]Wrap chart cascade delete indb.transaction()and addspanAnnotationsdeletion insrc/app/api/charts/[id]/route.ts - 4.9
[haiku]AddparseInt(value, 10)withisNaN()guard to all routes parsing integer query params - 4.10
[sonnet]Add CSV injection protection (prefix=+@-cells with') to all export routes - 4.11
[sonnet]Addresponse.okchecks before.json()insrc/app/page.tsx(lines 214, 230, 245, 257) - 4.12
[sonnet]Addresponse.okchecks before.json()insrc/components/CandleChart.tsx(lines 163, 178, 192)
5. ML Service Hardening (Python)
- 5.1
[sonnet]Replaceerror.message/ traceback details with generic"Internal server error"in FastAPI exception handlers at lines 640, 778, 1091, 1134, 1199, 1296 ofservices/ml/app/main.py - 5.2
[opus]Add SHA256 model integrity check: createmodels/checksums.sha256manifest, verify hash beforejoblib.load()inservices/ml/app/main.py:266 - 5.3
[sonnet]Add_model_swap_lockto prediction reads (not just writes) inservices/ml/app/main.pyfor thread-safe model access - 5.4
[sonnet]Add date range validation (max 1 year) toPOST /predict/batchinservices/ml/app/main.py - 5.5
[sonnet]Add candle time-sort validation/auto-sort toPOST /predictinservices/ml/app/main.py - 5.6
[sonnet]Implement real health checks:SELECT 1for PostgreSQL, MLflow API ping inservices/ml/app/main.py:396-409 - 5.7
[sonnet]Add training resource limits: 500MB dataset size check, 30-minute timeout with status update on expiry inservices/ml/app/main.py:907-1030 - 5.8
[haiku]Addrun_idformat validation toDELETE /training/runs/{run_id}andGET /training/runs/{run_id}endpoints
6. Infrastructure & Docker
- 6.1
[sonnet]Addheaders()function tonext.config.jswith X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy, Content-Security-Policy - 6.2
[sonnet]AddUSER appusertoservices/ml/Dockerfile: create user withuseradd, set ownership, add USER directive before CMD - 6.3
[haiku]Create.dockerignorewith.git,.env,.env*,node_modules,.next,data/,*.md,__pycache__/,mlruns/,models/ - 6.4
[haiku]Change TA-Lib download URL to HTTPS inservices/ml/Dockerfile:10 - 6.5
[sonnet]Add SHA256 checksum verification for TA-Lib download inservices/ml/Dockerfile - 6.6
[haiku]RemoveCOPY --from=builder /app/node_modules ./node_modulesline fromDockerfile:29(standalone doesn't need it) - 6.7
[sonnet]Pin Docker base images to@sha256:digests in both Dockerfiles - 6.8
[haiku]Fix healthcheck tool mismatch: use same tool (curl) in Dockerfile and docker-compose.yml
7. Frontend — Stale Closures & Race Conditions
- 7.1
[opus]Fix stale closure infetchPredictions: extractmodelInfointo auseRefthat stays in sync with state, use ref ingenerateCacheKey(src/app/page.tsx:489-552) - 7.2
[opus]Add AbortController tofetchPredictionsandhandleFetchBatchPredictions: store controller in ref, abort previous on new request, discard stale responses (src/app/page.tsx:494-663) - 7.3
[opus]Fix stale closure in CandleChart click handler: convertdrawingState,selectedLineId,dragState,annotationsto refs, update refs alongside setState, read refs in handler (src/components/CandleChart.tsx:572-971) - 7.4
[opus]Fix stale closure in SpanAnnotationManager keyboard handler: wraphandleDeleteSpaninuseCallback, use ref forselectedSpanId(src/components/SpanAnnotationManager.tsx:461-535)
8. Frontend — Memory Leaks & Performance
- 8.1
[opus]Fix SpanAnnotationManager preview primitive memory leak: replaceuseStatewithuseReffor preview primitive, add cleanup on unmount (src/components/SpanAnnotationManager.tsx:265-324) - 8.2
[sonnet]Usechart.applyOptions()for theme changes instead of re-creating chart (src/components/CandleChart.tsx:333) - 8.3
[sonnet]RemovefitContent()from reconciliation effect, only call on initial load (src/components/SpanAnnotationManager.tsx:160) - 8.4
[opus]Implement incremental primitive updates in SpanAnnotationManager: update only selection state on selection change, full reconciliation only on annotation list changes (src/components/SpanAnnotationManager.tsx:104-161) - 8.5
[sonnet]Add bounded prediction cache (max 100 entries, FIFO eviction) topredictionCacheRef(src/app/page.tsx:195-199) - 8.6
[sonnet]Fix hardcoded 1-minute candle interval: detect interval from data, use for span iteration (src/components/CandleChart.tsx:452) - 8.7
[haiku]Extract magic numbers (8px, 60s, colors) to named constants inCandleChart.tsx - 8.8
[haiku]Movenew Set<string>()default prop to module-level constant inCandleChart.tsx:125
9. Frontend — Shared Types & Type Safety
- 9.1
[sonnet]Createsrc/types/candles.tswithCandleinterface - 9.2
[sonnet]Createsrc/types/annotations.tswithAnnotation,AnnotationType,Geometryinterfaces - 9.3
[sonnet]Createsrc/types/charts.tswithChartinterface - 9.4
[sonnet]Createsrc/types/predictions.tswithPredictionSpan,PredictionState,ModelInfointerfaces - 9.5
[sonnet]Createsrc/types/span-annotations.tswithSpanAnnotation,SpanLabelType,SubSpaninterfaces - 9.6
[haiku]Createsrc/types/index.tsbarrel file re-exporting all types - 9.7
[sonnet]Replace duplicate interfaces inpage.tsx,CandleChart.tsx,SpanAnnotationManager.tsx,Toolbox.tsx,SpanAnnotationList.tsx,SpanPopover.tsxwith imports from@/types - 9.8
[sonnet]Replace allanytypes with proper interfaces:geometry→Geometry | null,sub_spans→SubSpan[], candle arrays →Candle[], prediction cache →Map<string, PredictionSpan[]>
10. Frontend — Error Boundary & UX
- 10.1
[sonnet]Createsrc/components/ErrorBoundary.tsxReact class component with error state, fallback UI (error message + "Try Again" + "Reload" buttons), andconsole.errorlogging - 10.2
[haiku]Wrap{children}with ErrorBoundary insrc/app/layout.tsx - 10.3
[sonnet]Add confirmation dialog before delete-all annotations insrc/app/page.tsx:412-425using Radix Dialog - 10.4
[haiku]FixSpanAnnotationList.tsx:110-115confidence check: replace falsy check with!= nullfor confidence value 0
11. Frontend — Accessibility
- 11.1
[sonnet]Addaria-labelattributes to all toolbar buttons inToolbox.tsx - 11.2
[sonnet]Addrole="dialog",aria-modal="true", and focus trapping toKeyboardShortcutsModal.tsx - 11.3
[sonnet]MakeChartSelector.tsxkeyboard accessible: add arrow key navigation and click-outside close handler - 11.4
[sonnet]Addaria-pressedto toggle buttons (span drawing mode, prediction visibility)
12. Frontend — Polish & Cleanup
- 12.1
[haiku]Remove unused importsTrendingUp,ChevronUpfromToolbox.tsx:4 - 12.2
[haiku]Remove@ts-ignoreinToolbox.tsx:246-247, replace with proper type assertion for CSS custom property - 12.3
[sonnet]Fix dark theme onannotation-types/page.tsxandspan-label-types/page.tsx: replace hardcoded light colors with theme-aware CSS variables - 12.4
[sonnet]Add debounce (150ms) oronPointerUpto confidence slider inPredictionPanel.tsx:148-155 - 12.5
[sonnet]Replace Google Font CSS@importinglobals.csswithnext/font/googleinlayout.tsx - 12.6
[haiku]Remove manual Escape handler inSpanPopover.tsx:114-117(conflicts with Radix Dialog) - 12.7
[sonnet]FixTalibPatternPanel.tsx:39re-fetch when API returns empty array: addhasLoadedflag - 12.8
[haiku]Add[candles]touseImperativeHandledependency array inCandleChart.tsx:202-221 - 12.9
[haiku]AddactiveChartIdto primitive cleanup effect dependency arrays inCandleChart.tsx:1059-1110 - 12.10
[sonnet]Implement or remove no-op Tooltip component inui/tooltip.tsx(replace with Radix Tooltip if used) - 12.11
[haiku]Removeeslint-disableinTrainingPanel.tsx:128-129, include stable callbacks in dependency array - 12.12
[haiku]Remove dead filter code (TODO comment, no-op) inpage.tsx:49-53
13. Package & Dependencies
- 13.1
[haiku]Move@types/node,@types/react,@types/react-dom,@types/papaparse,@types/pgfromdependenciestodevDependenciesinpackage.json - 13.2
[haiku]Movetypescript,eslint,eslint-config-next,autoprefixer,postcssfromdependenciestodevDependenciesinpackage.json - 13.3
[haiku]Addzodtodependenciesinpackage.json
14. Dead Code Removal
- 14.1
[haiku]Deletesrc/lib/db/migrate.ts(dead SQLite migration code) - 14.2
[haiku]Removeget_db_session()function fromservices/ml/app/db.py:99-111 - 14.3
[haiku]Remove deadinference*package reference frompyproject.toml:32 - 14.4
[haiku]Fix inconsistentuuid as uuid_libimport inservices/ml/app/main.py:9— use standardimport uuid - 14.5
[haiku]Remove duplicateTALIB_PATTERNSdict — import from one location (app/patterns.pyorgenerate_talib_annotations.py)
15. Deprecated Python API Replacements
- 15.1
[sonnet]Replace@app.on_event("startup")with FastAPI lifespan pattern inservices/ml/app/main.py:307 - 15.2
[haiku]Replacedeclarative_base()withclass Base(DeclarativeBase)inservices/ml/app/db.py:45 - 15.3
[haiku]Replace alldatetime.utcnow()withdatetime.now(datetime.UTC)inservices/ml/app/main.py:325,1000,1019,1080 - 15.4
[haiku]Add missing fallback return for volume indicators infeatures/talib_features.py:169-190