Files
ai-contract-platform/mobile/STATUS.md
T

29 KiB

Mobile scaffold status

Created on 2026-04-18.

  • Flutter scaffold added under mobile/
  • Android-first app shell uses bottom navigation for core V1 flows
  • Theme, asset folders, config placeholders, and lightweight session/network placeholders are ready for follow-up work
  • Backend integration, generated Flutter platform folders, and real assets are intentionally not included yet

Auth/session progress

  • apiBaseUrl is now pointed at local Android emulator backend routing (http://10.0.2.2:8000/api/v1)
  • http dependency added for real API calls
  • Mobile login flow now calls /auth/login
  • Current-user sync now calls /auth/me
  • Session state now hydrates from secure storage on app start and automatically migrates any legacy SharedPreferences session blob forward
  • In-memory session state continues to broadcast through ValueNotifier
  • App shell now gates the main tabs behind a login screen when no session exists
  • Dashboard and profile now reflect real login/session state instead of pure placeholder copy

Review entry progress

  • review_entry_screen.dart is now a real editable form instead of placeholder blocks
  • The mobile side now captures:
    • contract text
    • contract type
    • review side (party_a / party_b)
    • optional file attachment
  • A draft/request model is defined in features/review/domain/review_draft.dart
  • A submission controller is defined in features/review/application/review_submission_controller.dart
  • Current submit action now goes through ReviewDraft -> ReviewSubmissionController -> ApiClient.submitReview()
  • /reviews now supports text-only, file-only, or text+file submission from the mobile draft/controller structure
  • File selection UI is present, but still depends on Flutter/file_picker runtime validation in a real mobile environment

Review history progress

  • ApiClient.fetchReviewHistory() now calls GET /reviews with the current bearer token
  • A list-domain model is defined in features/review_history/domain/review_history_item.dart
  • A history controller is defined in features/review_history/application/review_history_controller.dart
  • review_history_screen.dart now loads and renders real list data for the current signed-in user
  • The mobile side can now form a basic path of login -> submit review -> view review history

Review detail/result progress

  • ApiClient.fetchReviewDetail() now calls GET /reviews/{review_id}
  • ApiClient.fetchReviewResult() now calls GET /reviews/{review_id}/result
  • features/review_history/domain/review_detail.dart and review_result_summary.dart provide the detail/result/report models
  • review_detail_controller.dart now loads task detail first and, for completed / partial, also loads result summary and report metadata
  • review_history_screen.dart can navigate from a list item into the detail/result screen
  • review_detail_screen.dart now renders task information, text preview, result summary, risk distribution, clause/risk counts, review opinion, and report metadata
  • Report flow now supports local download, direct open, system share, and copy-link action through a dedicated report controller
  • Mobile chat now has a first Review -> Chat flow: detail page can open a context-aware review assistant screen and stream answers from /chat/stream
  • The chat screen carries review_context, preserves conversation_id for continuous follow-up, and shows source cards plus a legal-use disclaimer
  • Dashboard now exposes an independent legal Q&A entry that reuses the same streaming chat surface without review_context
  • Chat now loads /conversations history and can reopen prior conversation detail, so independent法律问答和审查追问都具备基础历史恢复能力
  • Contract generation now has a mobile surface: template list, variable form, preview, generate, result display, and local file actions
  • Contract generation history is now visible on mobile with keyword search, contract-type filtering, pagination, and reopen-to-detail flow
  • Review detail can now jump into contract generation with review-derived prefill so title/type/risk/advice can land in matching template variables
  • Contract generation history can now reopen a prior result into the builder for continued editing and re-generation
  • Contract builder now lets the user switch export format (docx/pdf/html/txt) before preview and generation
  • Generated contract result screen can also continue editing from the current generated payload instead of forcing the user back to the history list
  • Chat bubbles now surface source relevance when available, and will explicitly warn when a round returns no directly citeable sources
  • Legal chat steadiness is now stronger on mobile:
    • assistant bubbles classify the answer into 已引用来源 / 通用建议 / 结论不确定 / 需补充资料
    • explicit no-answer wording now renders as a clearer refusal state instead of a generic fallback warning
    • no-source or guidance-only rounds now show a structured explanation with suggested next steps
    • the source panel is now grouped into 直接来源 and 辅助提示, with expandable evidence cards and simple relevance labels
  • The detail screen now supports pull-to-refresh and app-bar refresh for status/result/report updates after submit
  • Review submit success now auto-navigates into the newly created detail page

Current limitation

  • Server-backed mobile login is now validated against 192.168.3.90; remaining runtime uncertainty is mainly around system-level open/share handlers on the emulator image
  • File upload support is now validated on ai-contract-platform-lite-api34; the current ai-contract-platform-atd34 image still lacks a file explorer that can answer ACTION_OPEN_DOCUMENT, so attachment picking remains device-image dependent rather than app-logic dependent
  • Report flow now downloads correctly from the deployed server, but emulator-side open/share still depends on which external handlers are available on the current device image
  • 独立法律问答入口和合同生成入口已补到工作台,但还没有扩展成底部 Tab
  • 合同生成虽然已经有历史、筛选、审查预填和继续编辑,但还没有接入更细的模板筛选体验,以及与 Web 端完全对齐的独立预览/恢复参数承接
  • Brand/image assets are still placeholders; asset constants are intentionally nulled until real png/svg resources are added

Phase 0/1 mobile structure progress

  • project-docs/移动端开发方案-2026-05-01.md now records the mobile product scope, IA, phased plan, and acceptance criteria
  • App shell now separates unauthenticated login from the signed-in bottom-navigation experience
  • Bottom navigation metadata is centralized in app/navigation/app_router.dart
  • Login screen no longer pre-fills demo credentials and now has basic local validation, loading state, password visibility toggle, and a productized hero
  • Dashboard now reads real review history and shows recent review counts, in-progress counts, high-risk counts, quick actions, and latest tasks
  • Profile now hides API diagnostics unless MOBILE_SHOW_DIAGNOSTICS=true
  • Review labels are centralized in shared/constants/review_labels.dart so mobile pages show Chinese contract types, statuses, risk levels, source types, and review sides
  • Review submission now validates file extension and 20MB maximum size before uploading
  • API exceptions now carry HTTP status codes; review list/detail/submission clear local session on 401/403

Verification note

  • flutter analyze passed
  • flutter test passed
  • flutter build apk --debug --dart-define=API_BASE_URL=http://192.168.3.90:8001/api/v1 --dart-define=APP_ENV=server-dogfood produced build/app/outputs/flutter-apk/app-debug.apk
  • Android emulator tooling is installed locally and the lightweight ai-contract-platform-atd34 AVD now boots successfully

Runtime validation update (2026-05-03)

  • Runtime validation used ai-contract-platform-atd34 against http://192.168.3.90:8001/api/v1
  • Login succeeded on-device and the session persisted after reinstall
  • Text-only review submission succeeded and auto-opened detail for review-369b53d5ecf1
  • Review history and review detail both rendered the new task correctly
  • Independent legal Q&A succeeded: a quick-prompt message created a new conversation record and returned a two-message session in /conversations
  • Review-context chat succeeded: follow-up messages were sent, streaming answers returned, source cards rendered, and history conversations were recorded
  • Contract generation succeeded end-to-end: template selection, variable fill, preview, and generate all passed; a generated file named 保密协议标准模板_20260503_125037.docx was returned on-device
  • Report download URL normalization was fixed in shared/network/api_client.dart; the report link now resolves to http://192.168.3.90:8001/api/v1/reviews/review-369b53d5ecf1/report/download
  • Report download was verified on-device and saved to /data/user/0/com.example.ai_contract_mobile/app_flutter/review_reports/review-report-review-369b53d5ecf1.pdf
  • Generated-contract download was verified on-device and saved to /data/user/0/com.example.ai_contract_mobile/app_flutter/generated_contracts/保密协议标准模板_20260503_125037.docx
  • Review attachment picking no longer throws an unhandled crash in app code; on the current ATD image the plugin returns invalid_format_type because no system file explorer is installed, and the UI now stays on-page with a friendly retry message
  • Review attachment picking was fully validated on ai-contract-platform-lite-api34: mobile-upload.txt was selected through DocumentsUI, cached by file_picker, and rendered back in the mobile review form
  • A real wireless Android device is now paired and reusable for dogfooding (model=M20201419, device=X60PRO, Android 11)
  • tools/reconnect-wireless-device.ps1 can now re-discover the current _adb-tls-connect mDNS endpoint, reconnect the phone, and re-apply long screen timeout / stay-awake settings
  • On the real device, DocumentsUI opens successfully and the app-side file picker no longer crashes; the current remaining friction is OEM-specific picker interaction plus wireless ADB instability during long unattended runs
  • Real-device attachment selection now succeeds end-to-end when the OEM picker receives an explicit select-confirm interaction; mobile-upload.txt was loaded through DocumentsUI, cached by file_picker, and rendered back into the mobile review form
  • Real-device report download was validated for member data: review-report-review-59c9d1a83e63.pdf downloaded to /data/user/0/com.example.ai_contract_mobile/app_flutter/review_reports/review-report-review-59c9d1a83e63.pdf
  • Real-device report open now hands the PDF off to an external viewer app; on this device the default handler is com.feimi.browser rather than a dedicated PDF app
  • Real-device contract download was validated for member data: 保密协议标准模板_20260503_125037.docx downloaded to /data/user/0/com.example.ai_contract_mobile/app_flutter/generated_contracts/保密协议标准模板_20260503_125037.docx
  • Real-device contract share now escalates into WeChat's chat target (com.tencent.mm/.ui.chatting.ChattingUI), which confirms system-level share handoff on this OEM build
  • Mobile review history, review detail, generated-contract history, and contract template loading now keep the last successful data set on transient non-auth failures instead of clearing the screen immediately
  • tools/reconnect-wireless-device.ps1 now retries mDNS discovery before failing, which reduces the number of manual reconnect attempts needed after the device rotates its wireless debug port
  • Remaining runtime edge: on the no-window ATD emulator, external viewer/share-target behavior is still device-image dependent, so open/share can be invoked but not yet fully asserted as a stable automated oracle

Runtime validation update (2026-05-04)

  • Runtime validation continued on the paired real device (model=M20201419, device=X60PRO, Android 11) against http://192.168.3.90:8001/api/v1
  • tools/reconnect-wireless-device.ps1 -ExpectedIp 192.168.3. -ConfigureDevice successfully rediscovered and reconnected the rotated wireless-debug endpoint (192.168.3.93:42823)
  • Server reachability was rechecked before validation; both http://192.168.3.90:8001/health and http://192.168.3.90:3003/ returned 200
  • A freshly seeded member session resumed correctly on-device and rendered the workbench header for Mobile Member · member
  • Member review history revalidation passed: the real device rendered review review-eecc2296519a with completed status, service contract type, party_a, and medium risk
  • Member review detail revalidation passed: the real device opened review-eecc2296519a, rendered the result summary, and exposed the report actions for review-report-review-eecc2296519a.pdf
  • Report share system handoff is now fully evidenced on the real device:
    • the app surfaced 已调起系统分享
    • Android raised android/com.android.internal.app.ChooserActivity
    • the chooser preview attached review-report-review-eecc2296519a.pdf
    • the chooser offered share targets including 发送给朋友, 添加到微信收藏, 打印, and 电子邮件
  • Member contract-history revalidation passed on-device:
    • the generated-contract history section rendered normally
    • the seeded item 保密协议标准模板_20260504_052610.docx appeared under 已生成合同历史
    • opening the history item reached the generated-result screen with file metadata, plus 继续编辑 / 下载合同 / 打开文件 / 分享合同
  • Session persistence is no longer plain SharedPreferences only:
    • SessionStore now writes to flutter_secure_storage
    • legacy SharedPreferences sessions are migrated forward on first hydrate
    • targeted unit coverage now locks both secure-storage hydration and legacy-session migration
  • Post-migration validation passed again:
    • flutter analyze --no-pub
    • flutter test --no-pub
    • flutter build apk --debug --no-pub --dart-define=API_BASE_URL=http://192.168.3.90:8001/api/v1 --dart-define=APP_ENV=server-dogfood
  • A new unattended helper now exists for real-device dogfooding:
    • tools/real-device-smoke.ps1 reconnects wireless ADB, checks server health, relaunches the app, captures dumpsys activity top plus uiautomator XML, and writes a timestamped artifact bundle
    • this reduces the amount of manual phone babysitting needed for routine “is the device still reachable and does the app still launch?” checks
  • tools/real-device-smoke.ps1 now supports smoke-depth profiles:
    • login-only for auth-entrypoint checks
    • shell-only for unattended signed-in shell checks
    • share-proof for deeper report-share chooser evidence on the proven X60PRO real-device profile
  • The depth profiles have now been exercised on the real device:
    • login-only returned SMOKE_OK=True
    • shell-only returned SMOKE_OK=True
    • share-proof returned SMOKE_OK=True, SHARE_CHOOSER_ACTIVITY=android/com.android.internal.app.ChooserActivity, and SHARE_PDF_PREVIEW_OK=True
  • Lightweight notification infrastructure is now in place:
    • flutter_local_notifications drives local notifications
    • workmanager registers periodic review-status polling on signed-in Android sessions
    • review submissions are added to a persistent watchlist
    • review history loads seed additional pending reviews into that watchlist
    • contract generation now emits a completion notification immediately
    • tapping a review notification routes back to review detail
    • tapping a contract notification routes back to generated contract detail
  • Notification implementation validation passed at code/build level:
    • flutter analyze --no-pub
    • flutter test --no-pub
    • flutter build apk --debug --no-pub --dart-define=API_BASE_URL=http://192.168.3.90:8001/api/v1 --dart-define=APP_ENV=server-dogfood
  • Chat steadiness validation passed at code/build level:
    • flutter analyze --no-pub
    • flutter test --no-pub
    • flutter build apk --debug --no-pub --dart-define=API_BASE_URL=http://192.168.3.90:8001/api/v1 --dart-define=APP_ENV=server-dogfood
  • Information architecture is now more formal for user-side AI workflows:
    • bottom navigation now includes a first-class AI工具 tab
    • 法律问答 and 合同生成 are no longer hidden only behind dashboard shortcuts
    • the new tools tab uses an in-place segmented switch, so both capabilities are promoted without overcrowding the bottom navigation
    • dashboard shortcuts still exist, but now jump into the dedicated tools tab instead of opening them as only workbench-level shortcuts
  • Brand and UI polish moved a step closer to a product surface:
    • BrandAssets now provides a shared palette, gradient hero band, and reusable brand mark
    • login was rewritten around the branded hero surface instead of the earlier placeholder shell
    • the dashboard now uses a cleaner action grid and a more productized workbench hero
    • the new AI工具 first-class entry now has its own hero and clearer switch surface, instead of reading like a debug container
  • Real-device runtime evidence for background scheduling exists:
    • adb shell dumpsys jobscheduler now shows com.example.ai_contract_mobile/androidx.work.impl.background.systemjob.SystemJobService
  • Remaining unattended-device wrinkle:
    • after reinstall, this OEM build can still surface a lockscreen/SystemUI overlay during smoke, so real-device-smoke.ps1 may produce a false negative even when MainActivity is already top-most in dumpsys activity top
  • Current Phase 6 status: the remaining runtime risk is no longer the report-share path itself; the major residual instability is still OEM wireless-ADB churn during long unattended sessions

UI cleanup update (2026-05-04)

  • Remaining visible mojibake in the main mobile workflow has now been cleaned from:
    • review labels
    • profile
    • review history
    • review detail
    • contract template list
    • contract builder
    • generated contract result
  • Product-surface polish continues to land in the core mobile flow:
    • login uses the branded hero surface and shared palette
    • dashboard uses a more productized action grid instead of a plain action list
    • the first-class AI工具 tab now sits inside the same visual language as login and workbench
  • Post-cleanup validation passed again:
    • flutter analyze --no-pub
    • flutter test --no-pub
    • flutter build apk --debug --no-pub --dart-define=API_BASE_URL=http://192.168.3.90:8001/api/v1 --dart-define=APP_ENV=server-dogfood
  • Shell-level regression coverage is now stronger:
    • app_shell_test.dart verifies the first-class AI工具 tab is visible for authenticated users
    • app_shell_test.dart also verifies the dashboard quick action for 合同生成 correctly jumps into the dedicated tools hub
  • Real-device smoke reporting is now clearer:
    • real-device-smoke.ps1 explicitly reports SMOKE_BLOCKER=device_locked when OEM keyguard/pattern unlock blocks unattended validation
    • real-device-smoke.ps1 also reports SMOKE_BLOCKER=login_required when reinstall/relaunch drops the app back to the login shell instead of the authenticated workbench
    • this avoids treating current lockscreen overlays as a generic unknown smoke failure
  • We also tried extending smoke toward unattended auto-login:
    • backend credentials for the seeded mobile member are still valid
    • the current blocker is the OEM input method on this phone, which mutates adb input text enough to make unattended credential entry unreliable
    • for now, login_required is still the honest result when the app falls back to the login shell
  • The strengthened shell and smoke tooling passed together:
    • flutter test --no-pub test/app_shell_test.dart
    • flutter test --no-pub
    • flutter build apk --debug --no-pub --dart-define=API_BASE_URL=http://192.168.3.90:8001/api/v1 --dart-define=APP_ENV=server-dogfood
    • real-device-smoke.ps1 -SmokeDepth shell-only now exits with a precise environment blocker when the phone is still pattern-locked

Real-device dogfood revisit (2026-05-04)

  • After the keyboard-avoidance login fix, the updated APK was reinstalled on the real device and manual login succeeded
  • Workbench dogfood passed on-device:
    • the branded workbench hero rendered
    • the bottom navigation now shows 5 tabs, including the first-class AI工具 entry
    • the workbench quick-action grid is visible on-device instead of the older plain action list
  • AI工具 dogfood passed on-device:
    • entering the tab opened the dedicated AI tools surface
    • the hero band and segmented switch rendered correctly
    • tapping 合同生成 successfully switched the embedded tool view away from legal chat
  • Review-detail dogfood passed on-device:
    • the history tab opened a completed review detail successfully
    • task metadata and result summary rendered on the updated product surface
    • the updated review-detail layout remained readable on the real device without the earlier mojibake-heavy copy
  • Profile dogfood passed on-device:
    • the 我的 tab opened the refreshed account surface successfully
    • account identity, role, tenant, and status rendered on the updated product surface
  • The remaining weak spot in this revisit is contract-history deep reopening inside the embedded 合同生成 tool view:
    • the formal tools entry and contract-generation switch render correctly on-device
    • but the revisit session repeatedly bounced between history/detail and tools surfaces before the history-result reopen could be re-proven in the same pass

Contract workspace refinement (2026-05-04)

  • The mobile contract-generation surface was restructured away from the old “template cards endlessly stacked down the page” layout
  • 合同生成 now behaves more like a compact workspace:
    • 开始生成
    • 历史结果 are now separated into clearer work areas instead of being flattened into one long scroll
  • Template cards were tightened into more scannable compact surfaces, and the history-result cards now present 查看结果 / 继续编辑 as their own focused actions
  • Code/build validation passed after the contract-workspace restructuring:
    • flutter analyze --no-pub
    • flutter build apk --debug --no-pub --dart-define=API_BASE_URL=http://192.168.3.90:8001/api/v1 --dart-define=APP_ENV=server-dogfood

Shared AI + admin snapshot update (2026-05-04)

  • The mobile plan's remaining P2 management-assist slice is now implemented in a lightweight form:
    • Profile shows Shared AI runtime status
    • admin sessions now get a read-only management snapshot
    • the snapshot aggregates knowledge-base status, template availability, audit activity, and governance queue summary
  • The backend now exposes:
    • /api/v1/system/shared-ai
    • /api/v1/system/admin-snapshot
  • Shared AI knowledge-base routing is now tighter:
    • backend shared-ai SDK no longer emits an empty bearer header when api_key is blank
    • remote shared-ai test deployment now uses a concrete SHARED_AI_PLATFORM_API_KEY
    • the deploy script now ensures the ai-contract-platform app registry/scopes exist on the shared-ai side
  • Remote web validation now confirms:
    • /knowledge-bases can show Hybrid retrieval mode for shared-ai-backed KBs
    • /profile continues to show Remote preferred + hybrid
  • New validation pass:
    • pytest tests/test_system_api.py tests/test_shared_ai_platform_client.py tests/test_knowledge_bases_api.py
    • flutter analyze --no-pub
    • flutter test --no-pub
  • Current plan status:
    • P0 complete
    • P1 complete
    • P2 functional scope now complete in lightweight delivery form
    • remaining risk is primarily environment/runtime stability, not missing product features from the mobile plan

Contract history real-device closure (2026-05-04)

  • Rebuilt and reinstalled the latest debug APK onto the real device:
    • flutter analyze --no-pub
    • flutter test --no-pub
    • flutter build apk --debug --no-pub --dart-define=API_BASE_URL=http://192.168.3.90:8001/api/v1 --dart-define=APP_ENV=server-dogfood
    • adb -s 192.168.3.93:39787 install -r D:\ai-contract-platform\mobile\build\app\outputs\flutter-apk\app-debug.apk
  • Real-device contract-history validation is now fully closed inside AI工具 -> 合同生成 -> 历史结果:
    • switched the embedded contract workspace into 历史结果
    • surfaced the latest generated contract card for 保密协议标准模板_20260504_053915.docx
    • confirmed the history card exposes both 查看结果 and 继续编辑
    • tapping 查看结果 opened the generated-contract result screen
    • returning to history and tapping 继续编辑 opened the contract builder with the same template context
  • The latest manual proof artifacts are in:
    • mobile/qa-artifacts/manual-contract-history/window_dump_view_result.xml
    • mobile/qa-artifacts/manual-contract-history/window_dump_continue_edit.xml
  • Practical device note:
    • forcing portrait (user_rotation=0) made the embedded contract workspace much more stable for real-device validation than the OEM landscape state

AI tools contract-page split (2026-05-04)

  • The AI工具 tab no longer embeds the full contract workspace inside the bottom portion of the tools surface
  • The tools hub now behaves as:
    • an in-place legal-chat surface
    • a dedicated 打开合同工作台 launch action for contract generation
  • Entering contract generation from:
    • the dashboard quick action
    • the AI工具 tab launch action now opens a standalone full-screen 合同生成 page instead of a cramped nested scroll region
  • Validation passed after the split:
    • flutter analyze --no-pub
    • flutter test --no-pub test/app_shell_test.dart
    • flutter build apk --debug --no-pub --dart-define=API_BASE_URL=http://192.168.3.90:8001/api/v1 --dart-define=APP_ENV=server-dogfood
  • Real-device proof now exists for the new launch shape:
    • the AI工具 tab shows a dedicated 打开合同工作台 button
    • tapping it opens a standalone page with app-bar title 合同生成
    • the standalone page shows the contract workspace header and the 模板 / 历史结果 split as a full-screen flow
    • manual proof artifacts are in mobile/qa-artifacts/manual-tools-standalone/

Direct contract launch cleanup (2026-05-05)

  • Navigation was simplified so the dashboard contract shortcut no longer routes through AI工具 and then auto-pushes the contract page
  • Current launch behavior is now split more cleanly:
    • dashboard 合同生成 quick action -> direct standalone 合同生成 page
    • AI工具 tab -> in-place legal chat plus an explicit 打开合同工作台 launch button
  • The old shell workaround based on ToolsHubView.contracts auto-launch was removed, so the tools tab is no longer carrying contract-page launch state inside the shell
  • Validation after the cleanup:
    • flutter analyze --no-pub
    • flutter test --no-pub test/app_shell_test.dart
    • flutter test --no-pub
    • flutter build apk --debug --no-pub --dart-define=API_BASE_URL=http://192.168.3.90:8001/api/v1 --dart-define=APP_ENV=server-dogfood

Standalone contract page polish (2026-05-05)

  • The standalone 合同生成 page was tightened from a documentation-heavy tool page into a denser mobile work surface
  • Main surface changes:
    • removed the larger explanatory header card
    • replaced the old always-open filter card with a compact toolbar
    • moved type filtering into a bottom-sheet filter flow
    • kept the main canvas focused on template/history lists instead of static explanation copy
    • added a lighter top bar with 模板 / 历史结果 counts
  • The standalone contract page now reads more like:
    • compact page heading
    • switch surface
    • search/refresh/filter tools
    • primary list content instead of "big description + big filter card + list pushed below"
  • Validation passed after the page polish:
    • flutter analyze --no-pub
    • flutter test --no-pub test/app_shell_test.dart
    • flutter test --no-pub
    • flutter build apk --debug --no-pub --dart-define=API_BASE_URL=http://192.168.3.90:8001/api/v1 --dart-define=APP_ENV=server-dogfood
  • Real-device confirmation exists for the polished standalone page:
    • the dashboard contract quick action still opens the standalone page directly
    • the page now shows the tighter top bar, compact toolbar, and direct template list presentation
    • proof artifacts are in mobile/qa-artifacts/manual-contract-polish/

Contract list-density polish (2026-05-05)

  • The standalone contract page was tightened again to feel more like a professional mobile workbench list:
    • top counts now react to live template/history data instead of staying static
    • template items were compressed into denser list rows with the primary action aligned inline
    • history items now use a tighter summary row, file-size/time metadata, and smaller result/edit actions
    • filter controls stay in the compact toolbar + bottom sheet instead of consuming a large permanent card
  • Validation after the list-density pass:
    • flutter analyze --no-pub
    • flutter test --no-pub
    • flutter build apk --debug --no-pub --dart-define=API_BASE_URL=http://192.168.3.90:8001/api/v1 --dart-define=APP_ENV=server-dogfood
    • latest APK reinstalled to the real device successfully