Backend (app-pfm-ocr-v2/backend): - Product/SKU scan feature complete: trained DINOv2 index (118 reference photos, 16 SKU classes) and YOLO classifier (83.3% top-1 val accuracy), fixed scripts/install-pipeline.sh (was missing ultralytics/torch), fully browser-verified end-to-end on /scan-pfm. Mobile m-scan-pfm page cancelled (Flutter app handles mobile; web UI is desktop-only for pipeline testing). - Fixed a real data-loss bug: Save Ground Truth (scan-pfm and the DO-flow's manual-label) was silently writing into the pfm-web-app container's ephemeral filesystem instead of the host, because /sources wasn't bind-mounted in docker-compose.yml. Added the mount, recovered an orphaned entry. - accounts.password is now bcrypt-hashed (bcryptjs, idempotent migration in db/init.ts) instead of plaintext; login route compares hashes. - /api/v1/documents/* (list, PUT, upload) now enforces real 401 auth, matching what the Flutter client already sends. The "classic" routes deliberately stay open — they're dev-only web UI with no login flow and won't exist in production. - OCR accuracy investigated end-to-end: real baseline is 95.10% overall (target met; accuracy_report.md was stale at 75.04%, now flagged). Fixed one genuine parser.ts bug (SO/DO field duplication in the global fallback regex); remaining gaps are OCR/layout-model limitations, not parser bugs. - Adopted a standalone copy of the fhanyuh/agents-settings e/n workflow scoped to backend/ (AGENTS.md Part A/B split, SKILLS.md, plans/, docs/), independent of the root copy which now covers Flutter only. - next-implementation.md deleted; content folded into backend/plans/next-enhancements.md for traceability. Root: - Adopted fhanyuh/agents-settings kit (AGENTS.md, SKILLS.md, plans/, docs/feature-list.md), scoped to the Flutter app only. - Pending documents queue now persists to Hive (lib/core/storage) instead of memory-only, surviving an app kill mid-upload. Removed backend_backup/ (stale Express/Prisma prototype, superseded by pfm-web-app) and the completed plans/next-enhancement-plan.md checklist. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
7.7 KiB
Next Enhancements (Flutter)
This file is the working backlog driven by the e/enhance and n/next triggers
defined in AGENTS.md, which now scopes this kit's automated
behaviors to the Flutter app only (see AGENTS.md's "Scope: excludes backend/").
Sections seeded 2026-07-08 from the real module structure of app-pfm-ocr-v2 (see
AGENTS.md's Adaptation Notes); tasks populated the same day via e/enhance,
grounded in a direct read of each module's current code rather than invented work.
backend/has its own, independent copy of this kit — backend/plans/next-enhancements.md, driven bybackend/AGENTS.mdPart B. This file no longer tracks backend work at all — the backend sections that briefly lived here (5-8, from the one backend-scopederun before the kit split) were removed 2026-07-08 now that the backend copy is the sole active backlog for that subtree.
Note: this repo already has an unrelated, pre-existing
plans/next-enhancement-plan.md(singular) — a[DONE]QA verification checklist. It is not part of this workflow and is left as-is; this file (plural) is the onee/nreads and writes.
Format
Tasks are grouped under a numbered section per module of the application. Each section gets exactly 3 tasks:
## 1. <Section / Module Name>
- **1.1** [TODO] <clear, specific description of the functional change>
- **1.2** [TODO] <...>
- **1.3** [TODO] <...>
When a task is picked up via n/next, its clarified acceptance criteria (from
AGENTS.md §2a) are appended directly under it as a short note, e.g.:
- **1.1** [TODO] <description>
- Acceptance: <1-3 line resolved scope, from the clarification step>
When complete, the status flips to [DONE] and the feature is logged in
docs/feature-list.md.
Sections (seeded from real modules — run e / enhance to fill in tasks)
1. Flutter — Auth & Splash
lib/features/auth/, lib/features/splash/
- 1.1 [TODO] Validate the stored token before treating the user as logged in.
AuthNotifier.checkLoginState()(lib/features/auth/auth_provider.dart:11-20) only checks that a token string exists inSharedPreferences— it never checks expiry or pings the server — so a stale/revoked token shows the camera screen and only fails later, silently, on the first real API call. - 1.2 [TODO] Add a global 401/403 response interceptor to the Dio client that force-logs-out and redirects to
/login, so an expired/revoked token surfaces as a clear re-login prompt instead of failing whatever screen happens to make the next API call. - 1.3 [TODO] Warn before logout if the in-memory pending documents queue (
pendingDocumentsProvider,lib/features/documents/pending_documents_provider.dart) has unsynced items. TodayCameraScreen's drawer logout (camera_screen.dart:367-370) callslogout()unconditionally, silently orphaning any in-flight uploads or unsent items.
2. Flutter — Camera Capture & Geotagging
lib/features/camera/
- 2.1 [TODO] Surface actionable, user-visible feedback when location can't be determined, instead of only logging it. Every failure path in
LocationService.determinePosition()(lib/core/location/location_service.dart) — services disabled, permission denied,deniedForever, or all four GPS-fix strategies failing — only callsdebugPrintand returnsnull; the driver gets no on-screen prompt (e.g. "enable location" / "open app settings") and the document just uploads without a GPS tag. - 2.2 [TODO] Show a location-fix quality/staleness indicator on the capture screen before the shutter is pressed.
_currentPositioninCameraScreen(camera_screen.dart:22,37-62) is used whatever its age or accuracy, with no on-screen warning when no fix has landed yet or the fix is old — a document can silently upload with a poor or missing GPS tag. - 2.3 [TODO] Replace the static "posisikan seluruh halaman dokumen di dalam foto" instructional text with a live document-alignment overlay during capture.
CameraScreenonly launches the OS's native camera app viaImagePicker(source: ImageSource.camera)(camera_screen.dart:69-74) — there's no in-app camera preview, so the framing guideline is shown once beforehand and then unavailable during the actual shot.
3. Flutter — Pending Documents Queue
lib/features/documents/
- 3.1 [DONE] Persisted the pending documents queue to disk via a new Hive box (
LocalStorage.pendingDocumentsBox/savePendingDocument/removePendingDocument/getAllPendingDocuments,lib/core/storage/local_storage.dart).PendingDocumentsNotifiernow hydrates from disk on construction and resumes anything not yet terminal: a persisteduploadingitem (fresh capture, or aretryUploadinterrupted mid-flight) re-runs_uploadAndProcessfrom scratch — safe because the upload endpoint dedupes by file hash server-side — and a persistedprocessingitem resumes polling via the newly extracted_pollUntilParsed/_resumePollinginstead of re-uploading.retrySync's own transient flip touploadingis deliberately kept in-memory-only (_updateItemInMemory) so an interrupted sync-retry resumes as "resend the PUT," not "redo the whole upload." Storage failures are caught and swallowed everywhere (hydrate,_persistPendingDocument,_removePersistedPendingDocument) so a Hive error degrades to the old in-memory-only behavior rather than crashing the queue. Verified viaflutter analyze(clean) andflutter test(no new failures vs. the pre-existing 3-test baseline). Completed 2026-07-08. - 3.2 [TODO] Add a persistent "pending/syncing count" badge visible from the camera screen (not just the
/documentslist), reflectingpendingDocumentsProviderstate — today a driver who navigates away from/documentsgets no visibility into background uploads still in progress or stuck inerror/syncFailed. - 3.3 [TODO] Add explicit Dio request timeouts to the upload and poll calls in
_uploadAndProcess(pending_documents_provider.dart:112-162). The 2s-interval/130-retry poll loop is intentional and bounded, but the underlyingapiClient.client.post/.getcalls themselves have no explicit connect/receive timeout, so a genuinely hung connection (not a slow-but-alive OCR pass) can leave an item stuck inuploadingindefinitely.
4. Flutter — Document Editor & PDF Receipt
lib/features/editor/
- 4.1 [TODO] Add an unsaved-changes guard when navigating away from
EditorScreenwith edited-but-unsaved field values. There is currently noPopScope/back-navigation interception, so a back-swipe or system back button silently discards manual corrections to OCR'd header/item fields. - 4.2 [TODO] Block save when a line item's SKU isn't in the master registry, instead of only relabeling it for display. The SKU listener in
_addItem(editor_screen.dart:108-115) sets the item name to "SKU Tidak Terdaftar" for an unrecognized SKU but doesn't stop form submission, so a document with an unregistered/mistyped SKU can still be saved and its receipt printed. - 4.3 [TODO] Include the captured GPS coordinates on the printed PDF receipt.
PdfService.generateAndPrintReceipt(pdf_service.dart:36-52) prints header/shipment/item fields but never includesdocument.latitude/longitude, even though the editor captures and displays them (_latitudeCtrl/_longitudeCtrl) — the geotag exists in the data model but isn't part of the audit-trail document a store keeps.
Sections 1-4 (Flutter) are the only sections this file tracks. Backend enhancements (formerly sections 5-8 here, removed 2026-07-08) now live exclusively in backend/plans/next-enhancements.md.