Commit Graph
46 Commits
Author SHA1 Message Date
MythEclipseandClaude ac59548337 feat(android): Google OAuth via system browser + deep link for Android
Background: Google blocks OAuth in embedded WebView (403 disallowed_useragent).
Solution: open Google login in the Android system browser, then deep-link
back to the Tauri app via custom scheme after callback.

Changes:
- Tauri: add tauri-plugin-opener + tauri-plugin-deep-link to Cargo.toml
- Tauri: register plugins in lib.rs, add capabilities
- Web: auth-form.tsx Google button uses openUrl() via @tauri-apps/plugin-opener
  on Tauri (opens in system browser), falls back to window.location.href
- Web: add lib/tauri.ts for isTauri() detection + lazy opens
- API: /auth/google accepts ?platform=tauri → encodes into OAuth state param
- API: /auth/google/callback decodes state → if tauri, renders HTML page
  that deep-links back via zeavisedu:// scheme; if web, 302 redirect
- Android: patch script adds deep link intent filter for zeavisedu:// scheme

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-15 23:49:47 +07:00
MythEclipseandClaude d47c73308e fix(auth): replace deprecated set.redirect with manual 302 Location header
Elysia's set.redirect returns 200 OK instead of 302 redirect on the
current version. Use set.status = 302 + set.headers['Location'] instead
for both /auth/google (Google OAuth redirect) and /auth/google/callback
(all redirect paths: errors, success token delivery).

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-15 22:06:59 +07:00
MythEclipseandClaude c9ae90a042 feat(auth): implement Google OAuth callback with user auto-creation
API (apps/api/src/routes/auth.ts):
- Exchange authorization code for tokens via Google's token endpoint
- Decode id_token payload (JWT) to extract sub, email, name
- Find user by googleId → fall back to email match (link accounts)
- Auto-create user if neither found (role: 'user', no password)
- Create session + set cookie, redirect to /login?token=<token>

Web (apps/web/src/pages/login-page.tsx):
- Consume ?token= query param from OAuth redirect
- Store token in localStorage for future API calls
- Fetch /auth/me to hydrate Zustand store, then navigate to dashboard
- Show OAuth errors from ?error= query param

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-15 21:35:40 +07:00
MythEclipseandClaude c881e6a2b2 fix(auth): pass request.headers to getCurrentUser in all protected routes
dashboard, diagnoses, expert routes now support Authorization header fallback for Android WebView

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-15 20:11:11 +07:00
MythEclipseandClaude 7693a02c98 fix(auth): add bearer token auth as fallback for Android WebView third-party cookie blocking
Android WebView blocks third-party cookies by default. This patch:
- Returns session token in login/register response body
- Stores token in localStorage, sends via Authorization: Bearer header
- Backend getCurrentUser supports Authorization header fallback

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-15 19:43:02 +07:00
MythEclipseandClaude 51a4cb9ed2 fix(auth): detect HTTPS via X-Forwarded-Proto for SameSite=None cookies, fix AuthGuard null overwrite
- Cookie SameSite now dynamic: None;Secure when behind HTTPS proxy, Lax otherwise
- AuthGuard useEffect no longer overwrites Zustand store with null from background refetch
- AuthInitializer: add staleTime 30s

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-15 18:17:26 +07:00
MythEclipse 22307d44de fix(api): add http://tauri.localhost to CORS allowed origins 2026-06-15 17:09:40 +07:00
MythEclipseandClaude 41e0501e6b fix(tauri): add absolute API base URL default and CORS origins for Android WebView
- Set VITE_API_BASE_URL default to production API URL in api-client.ts
  so fetch() uses absolute URLs instead of relative paths that fail on Tauri
- Add tauri://localhost and https://tauri.localhost to API CORS allowed origins
- Also fix .env WEB_APP_URL from stale .tech to .my.id

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-15 14:32:54 +07:00
MythEclipseandClaude bf1725a4b8 fix(docker): remove non-existent shared/node_modules COPY from API Dockerfile
packages/shared has only devDependencies (typescript). After
bun install --production, packages/shared/node_modules does not
exist. Root node_modules contains all hoisted deps.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-15 13:58:23 +07:00
MythEclipseandClaude 8954535e08 fix(ci): add tauri package.json to Dockerfiles and fix Android NDK/build issues
Build and Deploy: workspace has 4 members (api/web/shared/tauri) but
Dockerfiles only copied 3 package.json files. Missing tauri workspace
member caused bun install --production to fail with frozen lockfile
error.

Build Android APK:
- Remove explicit NDK 28 install (runner has NDK 29 pre-installed, dual
  NDK presence broke ANDROID_NDK_HOME resolution)
- Auto-pin NDK version from runner's SDK
- rm -rf gen/android before tauri android init (stale cache recovery)
- Remove gen/android/.gradle from Gradle cache (causes stale state)
- Use --apk flag for faster APK-only build

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-15 13:54:55 +07:00
MythEclipseandClaude b93be6c6cb fix(docker): copy bun.lock and workspace node_modules to API runner stage
Bun workspace symlinks (apps/api/node_modules/*) pointed to root
.bun cache but were never copied from deps→runner. Added bun.lock,
apps/api/node_modules, and packages/shared/node_modules to the
runner COPY chain so  and  resolve at runtime.

Also added bun.lock to web Dockerfile for deterministic installs.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-15 03:30:18 +07:00
MythEclipseandClaude 05055ed9cf fix(ci): remove bun.lock from Docker COPY to avoid version mismatch
Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-15 01:17:25 +07:00
MythEclipseandClaude 02ae022174 fix(ci): regenerate bun.lock and disable frozen-lockfile in Dockerfiles
bun auto-enables --frozen-lockfile in CI by default. Use env var
BUN_INSTALL_FROZEN_LOCKFILE=0 to override this behavior. Also
regenerate lockfile fresh to ensure it is compatible with bun 1.3.14.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-15 01:06:17 +07:00
MythEclipseandClaude 9ee3af8a1f fix(ci): add --no-frozen-lockfile to bun install in Dockerfiles
bun defaults to --frozen-lockfile in CI environments, causing failures
when the lockfile format differs from the version used at build time.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-15 01:02:35 +07:00
MythEclipseandClaude 3d3ca72230 fix(ci): remove --frozen-lockfile to prevent bun version mismatch failures
CI uses bun 1.3.14 (stable) but local dev uses canary. Lockfile
format can differ between versions causing spurious failures.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-15 00:57:31 +07:00
MythEclipse b0dd1f289a chore(api): update uploader base URL domain
Update the default `uploaderBaseUrl` from `.tech` to `.my.id` due to the
previous domain being decommissioned.
2026-06-08 01:53:02 +07:00
MythEclipse c45f771f24 feat(telemetry): add comprehensive Prometheus metrics and expand dashboard with system, API, ML, and Node.js runtime sections 2026-06-08 01:20:42 +07:00
MythEclipse ede1c480be feat(api): add Prometheus metrics and OpenTelemetry instrumentation for HTTP, auth, classifications, and diagnoses 2026-06-07 18:12:32 +07:00
Asep Haryana SaputraandClaude Opus 4.7 1978597bcf feat: add Docker deployment workflow
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-22 21:20:56 +00:00
Asep Haryana SaputraandClaude Opus 4.7 e84be0d42f fix: handle malformed ML service responses
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-22 20:00:01 +00:00
Asep Haryana SaputraandClaude Opus 4.7 b81fecaa3f chore: remove API local model dependencies
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-22 19:54:31 +00:00
Asep Haryana SaputraandClaude Opus 4.7 1689f3f44e feat: call ML service for image classification
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-22 19:53:10 +00:00
Asep Haryana SaputraandClaude Opus 4.7 9a642a8581 feat: add ML service URL config
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-22 19:50:25 +00:00
Asep Haryana Saputra 8415cbb2de feat: add database seeding script for disease catalog and expert user 2026-05-22 18:54:23 +00:00
Asep Haryana Saputra 1f4e0fbef3 fix: update environment variable usage in scripts and enhance CSS theming 2026-05-22 18:50:07 +00:00
Asep Haryana Saputra ab81168be7 chore: update dependencies and build scripts
- Updated @moonrepo/cli to version 2.2.5 and typescript to version 6.0.3 in package.json and shared package.json.
- Modified build script in package.json to run shared, api, and web builds.
- Removed unnecessary type and language declarations from shared moon.yml.
- Added ignoreDeprecations option in tsconfig.base.json to handle TypeScript 6.0 deprecations.
2026-05-22 18:30:40 +00:00
Asep Haryana SaputraandClaude Opus 4.7 c623de9959 fix: harden production auth and review flow
- Add environment-aware CORS and secure cookie support:
  * Add secureCookies config to env.ts based on SECURE_COOKIES env var or https detection
  * Integrate @elysiajs/cors with credentials and origin configuration
  * Update cookie helpers to use SameSite=None; Secure in production
- Wrap expert review update and insert in database transaction for atomicity:
  * Ensures diagnosis status update and review insert succeed together
  * Rolls back both operations if either fails
  * Preserves behavior: only update if status is needs_review, return badRequest if no row updated

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-22 17:32:57 +00:00
Asep Haryana Saputra 4478d51aae feat: add production MVP database migration 2026-05-22 17:19:46 +00:00
Asep Haryana Saputra e9d6aabcdc fix: tighten dashboard summary types 2026-05-22 16:39:38 +00:00
Asep Haryana Saputra 02b002b021 feat: update dashboard for diagnosis workflow 2026-05-22 16:36:53 +00:00
Asep Haryana SaputraandClaude Opus 4.7 7712a5c6a1 fix: prevent duplicate expert reviews
In POST /reviews/:diagnosisId, perform the conditional diagnoses update
first with .returning() to determine whether a row was updated. The update
WHERE includes both id and status 'needs_review'. If no row is returned,
return badRequest and do not insert an expert review. Only after a
successful update insert expertReviews. This prevents concurrent reviewers
from both inserting review rows when only one update should win.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-22 16:34:02 +00:00
Asep Haryana SaputraandClaude Opus 4.7 d72eaffb6b fix: guard expert review state
- Reject diagnoses not in needs_review status with badRequest
- Make update conditional on both id and status needs_review using and()
- Simplify isDiagnosisRecordOrNull type guard with type alias

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-22 16:30:17 +00:00
Asep Haryana Saputra 59204b0fde feat: add expert diagnosis review workflow 2026-05-22 16:23:40 +00:00
Asep Haryana SaputraandClaude Opus 4.7 afa2e4999b fix: type diagnosis record mapping
- Replace `function toReview(row: any)` with typed ReviewRow interface
- Reconstruct DiseaseCatalogItem explicitly from selected fields instead of casting
- Replace `.filter(Boolean)` with typed isDiagnosisRecord predicate
- Add proper type narrowing for verdict and correctedDiseaseSlug in toReview

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-22 16:19:10 +00:00
Asep Haryana SaputraandClaude Opus 4.7 2e692a4b8c fix: tighten diagnosis route typing
Replace unsafe `as any` casts with proper type guards using `isDiseaseSlug()`
and explicit type casting to `DiagnosisStatus` and `DiseaseCatalogItem`.
Replace non-null assertions with explicit null checks that return
`serviceUnavailable()` errors when database operations fail.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-22 16:15:45 +00:00
Asep Haryana SaputraandClaude Opus 4.7 1a36ae5cbc feat: persist authenticated diagnoses
Implement diagnosis persistence routes with image upload, classification,
and prediction storage. Add missing HTTP error helpers (unauthorized,
forbidden) and update uploader client to use configurable base URL.

- Create POST /api/v1/diagnoses to upload images and store classifications
- Create GET /api/v1/diagnoses to list user's diagnoses (30 most recent)
- Create GET /api/v1/diagnoses/:id to retrieve diagnosis with predictions
- Add loadDiagnosisRecord helper for consistent diagnosis data loading
- Update uploader-client.ts to use env.uploaderBaseUrl
- Add unauthorized and forbidden error helpers to http-errors.ts
- Register diagnosisRoutes in main app

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-22 16:08:18 +00:00
Asep Haryana Saputra 5eb195cbeb feat: add session auth routes 2026-05-22 16:00:47 +00:00
Asep Haryana Saputra 794abfdb35 feat: add production auth and diagnosis schema 2026-05-22 15:53:48 +00:00
Asep Haryana Saputra 15c6be9e84 feat: implement backend image classification with TensorFlow.js model
- Extend shared types for image classification, including PredictionProbability, UploaderMetadata, and ImageClassificationRecord.
- Create image_classifications table in the database with necessary fields and foreign key constraints.
- Implement disease mappers to convert database rows to shared disease records.
- Develop uploader client to handle image uploads to external service.
- Create image model service to load and classify images using TensorFlow.js.
- Add API routes for image classification, including GET for history and POST for new classifications.
- Implement frontend components for image classification form and display results.
- Update dashboard to integrate image classification functionality and display results.
- Document implementation plan for backend image classification.
2026-05-22 15:13:22 +00:00
Asep Haryana Saputra 84c1f46841 Implement fullstack education catalog with disease detail pages, API routes, and shared types
- Add disease detail page component with data fetching and error handling
- Create shared types for diseases and classifications
- Implement API routes for diseases, classifications, and dashboard summary
- Develop reusable components for risk badge and disease card
- Build catalog page with search and filter functionality
- Update dashboard page with data-backed summary and manual classification form
- Register new routes in the web application
- Ensure type safety and consistency across shared modules
2026-05-22 14:26:13 +00:00
Asep Haryana Saputra 1712108382 Document fullstack app commands and fix Moon config 2026-05-22 13:04:43 +00:00
Asep Haryana Saputra da18375c92 Verify fullstack scaffold builds
- Install bun dependencies and generate bun.lock
- Add @types/bun to API dev dependencies for Bun type support
- Add @types/react and @types/react-dom to web dev dependencies
- Fix web tsconfig.node.json composite project emit configuration
- Verify all packages typecheck and build successfully
- Verify API health and status endpoints respond correctly

All verification steps passed:
- bun install: 354 packages installed
- packages/shared typecheck: OK
- packages/shared build: OK (dist generated)
- apps/api typecheck: OK
- apps/api build: OK (0.76 MB bundle)
- apps/web typecheck: OK
- apps/web build: OK (dist generated)
- API /health endpoint: {"status":"ok"}
- API /api/v1/status endpoint: {"name":"ZeaVis Edu","status":"ok","version":"0.1.0"}
2026-05-22 12:53:15 +00:00
Asep Haryana Saputra 393779f81d Include shared outputs in API typecheck inputs 2026-05-22 12:36:05 +00:00
Asep Haryana Saputra 33ada3f1a7 Include shared outputs in API build inputs 2026-05-22 12:33:20 +00:00
Asep Haryana Saputra 2e64e67156 Link API tasks to shared package build 2026-05-22 12:28:54 +00:00
Asep Haryana Saputra 5e38c9276a Add Elysia API scaffold 2026-05-22 12:25:41 +00:00