Files
verde-scanner/analysis_options.yaml
admin 0b2244fbf7 feat(mobile-scanner): scaffold + Phase 1 — full scan flow
Flutter app for scanner staff at drop-off points, package
ph.verde.verde_scanner. Built on the same foundation as
mobile-driver — Riverpod 2, Dio, go_router, secure_storage —
plus mobile_scanner for native MLKit-backed QR/Code-128 detection.

Backend:
- DropOffPointResource now exposes db_id alongside the public uuid.
  The /scanner/scan endpoint takes the integer drop_off_point_id, so
  the picker screen needs both to resolve a tap → scan target.

Auth + tenancy (mirrors driver app):
- Tenant gate at /tenant with the same SAN-PASCUAL-BAT shortcut.
- Login validates user.role ∈ { scanner, admin } and stashes the
  bearer in keychain.
- ResolveTenant headers attached automatically on every request.

DOP picker (new):
- /dop screen lists drop-off points within 50 km of current GPS,
  sorted by distance. Pick one → stored in secure storage as the
  active session DOP. The router redirects authenticated scanners
  here until they pick.
- GPS prompt screen if location services / permission are missing,
  with retry.

Home screen (new):
- "STATIONED AT" banner showing the active DOP with a Change link
  that returns to the picker.
- Premium gradient "Start scanning" CTA. Disabled until a DOP is
  picked.
- Two stat counters (accepted / total) for the current session.
- Recent scans list with outcome-colored icons.

Camera scan screen (new):
- mobile_scanner with QR + Code-128 formats and noDuplicates speed.
- Verde reticle overlay with corner brackets, dimmed surroundings.
- Bottom translucent banner shows active DOP + accepted count.
- Full-screen toast overlay on every scan: green "Accepted" / amber
  "Duplicate" / red "Expired" / red "Invalid" / gray "Network
  error". Haptic + system click on accept. 1.5 s cooldown so the
  same code can't pump.
- Torch + camera-flip controls top-right.

Data layer:
- DopRepository: GET /drop-off-points/nearby, returns DopOption with
  both id and uuid.
- ScanRepository: POST /scanner/scan with current GPS, maps the
  backend's "rejected: reason[]" response onto a typed ScanOutcome
  (accepted / duplicate / expired / invalid / networkError).
- RecentScansController: in-memory ring buffer capped at 50.
  Phase 2 will persist + add an offline buffer.

Permissions:
- iOS Info.plist: NSCameraUsageDescription + NSLocationWhenInUseUsageDescription.
- Android manifest: CAMERA + ACCESS_FINE_LOCATION + INTERNET +
  uses-feature camera.

Tests: TenantScreen builds. flutter analyze: 6 style infos, no errors.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 23:49:20 +08:00

29 lines
1.4 KiB
YAML

# This file configures the analyzer, which statically analyzes Dart code to
# check for errors, warnings, and lints.
#
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
# invoked from the command line by running `flutter analyze`.
# The following line activates a set of recommended lints for Flutter apps,
# packages, and plugins designed to encourage good coding practices.
include: package:flutter_lints/flutter.yaml
linter:
# The lint rules applied to this project can be customized in the
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
# included above or to enable additional rules. A list of all available lints
# and their documentation is published at https://dart.dev/lints.
#
# Instead of disabling a lint rule for the entire project in the
# section below, it can also be suppressed for a single line of code
# or a specific dart file by using the `// ignore: name_of_lint` and
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
# producing the lint.
rules:
# avoid_print: false # Uncomment to disable the `avoid_print` rule
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options