Athena — auditPic/planning/session-handoff-2026-05-18.md

AuditPic — session handoff · 2026-05-18

Wrap-up of the multi-PR session that shipped account/quota/security work. Use this to pick up cleanly in the next session.


What landed (merged to main)

| PR | Closes | Brief | |---|---|---| | #62 | #52 | Jailbreak / root detection. flutter_jailbreak_detection, SecurityGate wraps runApp, IntegrityBlockedScreen for prod, warn-banner for staging, allow on local. Maestro flow .maestro/security/integrity_blocked.yaml. | | #63 | #50 | Burned-in timestamp + GPS footer on every captured photo. New WatermarkService (pure function over bytes), LocationProvider, geolocator permission strings on iOS/Android. 10 unit tests covering footer-band darkness, timestamp variance, null-location fallback, decode-failure fail-closed. | | #65 | #57, #58 (see note) | V10 migration: users.tier, users.email_verified, users.subscription_status/_provider/_external_id, with grandfather backfill. Tier enum (FREE 20/mo, PRO 500/mo, BUSINESS 5000/mo, ENTERPRISE unlimited). QuotaService + QuotaExceededException → 402 with snapshot in body. GET /api/v1/me. PhotoController calls assertCanUpload before MinIO. 7 QuotaServiceTest cases. | | #68 | refs #53 | Cert pinning (sha256/<hex> over DER) on both Dio instances. Parser unit tests; SPKI upgrade noted as a #53 sub-task. | | #74 | #71 | In-app account deletion (App Store 5.1.1(v)). Settings entry on Gallery AppBar → typed-confirmation screen → DELETE /api/v1/auth/me → clear secure storage → /login. Maestro flow .maestro/settings/delete_account.yaml runs last in the CI sequence (it destroys the test user). |

Issues that didn't auto-close

PR #65's body said Closes #57 and #58. GitHub recognised the first reference but not the second one after and#58 is still listed open even though it's implemented. #57 is also still listed because the email-verification flow (the verify-email endpoint + SMTP wiring) wasn't shipped in this PR; only the schema + grandfather backfill. Treat #58 as effectively closed, #57 as partially done.


Still open — PRs

| PR | Status | Action | |---|---|---| | #61 | OPEN, mergeable=CONFLICTING | Has the format fix (2b3819b style: apply dart format to capture_camera_only_test.dart) but the merge state went dirty after #62/#63/#74 landed (gallery_screen.dart touched in #74, and pubspec.yaml/capture_screen.dart touched in #63). Rebase onto current main, push, merge. Contents are tiny — only capture_screen.dart comment + test/security/capture_camera_only_test.dart. |


Still open — issues (and what's left to build)

Security epic #53 — phases not yet shipped

PR #68 covered TLS pinning. Remaining sub-items, each its own future PR:

  • Disable screenshots / screen recording on capture screen (iOS UIScreen.captured, Android FLAG_SECURE)
  • Anti-debugger / anti-instrumentation (Frida detection)
  • Biometric unlock + auto-lock on backgrounding (local_auth)
  • Wipe in-memory plaintext after upload
  • Clock-skew check vs server (refuse capture if device clock > 30 s off)
  • iOS App Attest + Android Play Integrity

Camera-only #51

Blocked only by #61 merge. Same conceptual work — just a structural guard test against gallery picker.

Monetization — #58, #59

  • #58 plan tiers — schema landed in #65; remaining work is mobile UI: upgrade-CTA banner, quota indicator on Gallery, plan badge on Profile. Backend already exposes /api/v1/me with the snapshot.
  • #59 Stripe Billing — scaffolding (BillingProperties, StripeCustomerService skeleton, application.yml billing.stripe block, pom.xml stripe-java dep) was left in a stash on the session machine because it depended on PR #65's User entity additions. Now that #65 is merged, that stash is safe to pop and finish: StripeWebhookController for customer.subscription.* and invoice.payment_*, CheckoutSessionController, BillingPortalController.

Email verification — #57 (residual)

  • New email_verification_tokens table (Flyway V11)
  • POST /api/v1/auth/verify/{token} + POST /api/v1/auth/resend-verification (rate-limited 1/min/email)
  • SMTP wiring — backend has no transport configured yet
  • Mobile: "check your inbox" screen after register, banner on authenticated screens while email_verified == false

Web — #70, #72, #73

Dependency chain:

#70 (Astro + Tailwind on Cloudflare Pages, marketing pages)
 ├── #72 (signup form → POST /api/v1/auth/register)
 └── #73 (authenticated dashboard: gallery, billing, account)
       depends on #59 for /dashboard/billing
       backend change: CORS allow https://auditpic.com

Each is a separate, multi-day build. Recommend starting with #70's skeleton (one Astro starter PR with routing + placeholder pages, no copy decisions baked in) and iterating from there.

Other open issues

  • #37 manual production setup checklist
  • #39 consolidate JWT + HMAC rotation into single workflow
  • #40 Java 17 → 21 bump (Java 17 EOL Sept 2026)
  • #43 document multi-project k3s tenancy model
  • #44 bump deprecated Node.js 20 GitHub Actions
  • #60 business plan doc tracking (draft already at docs/auditPic/business/business-plan.md)

Known CI / process gaps

Backend CI doesn't compile on PRs

ci-backend.yml only triggers on backend path changes (correct — saves CI minutes). But the build-push job is gated by if: github.event_name == 'push', so PRs validate tests but never run mvn clean package. A PR can pass tests while breaking the Docker image build — caught only after merge.

Fix: split build-push into:

  • build job — mvn clean package -DskipTests, runs on PR + push
  • push job — Docker login + tag + push, runs only on push

Small workflow edit, no logic change. Future-session PR.

dart format --set-exit-if-changed is a sharp edge

Every Flutter PR this session tripped it. The local flutter analyze is permissive but the CI step is strict. Two cheap fixes:

  1. Add a dart format --set-exit-if-changed . pre-commit hook so it bites before push.
  2. Or add a make fmt target that runs the same command and document it in CONTRIBUTING.

Parallel-session branch tangling

Multiple parallel sessions (other agent + this session) check out branches behind each other's back. Symptoms seen this session:

  • A push to feat/security-hardening-phase1 landed on a local branch named fix/flutter-staging-baseurl.
  • git checkout reported "Already up to date" on a branch with a different SHA on the remote.
  • Local commit ended up on hotfix/tmp-volume-for-tomcat even though I had just git checkout -b feat/accounts-and-plans.

Workaround for next session: when creating a PR branch, git checkout -B <branch-name> origin/main (capital B forces a reset) and git rev-parse --abbrev-ref HEAD to verify before each commit. Avoid trusting the working tree implicitly.

image_picker is still in pubspec.yaml

#51 chose to lock the capture flow structurally rather than remove the dependency. Long-term, the camera-package migration in the security epic should drop image_picker entirely.


Recommended next-session order

  1. Merge PR #61 (rebase first — conflict on pubspec.yaml, capture_screen.dart, gallery_screen.dart after the three October merges; resolve trivially).
  2. Close issues #57 + #58 manually with cross-links to PR #65 (since Closes #57 and #58 only caught the first one).
  3. Fix the backend-build-on-PR gap — split build-push job. 30-line workflow change.
  4. Email verification flow to actually fulfill #57 — Flyway V11 + endpoints + SMTP. Probably the most blocked piece of the monetization story.
  5. Pop the Stripe stash from the session machine and finish #59 on top of merged #65.
  6. Mobile UI for #58 (upgrade-CTA, quota indicator) — backend /api/v1/me is already there.
  7. Start the web site skeleton (#70) — Astro repo scaffold, routing, placeholder pages. Iterate from there.

Useful references

  • Business plan (draft v0.1): docs/auditPic/business/business-plan.md
  • Codemagic + Apple team gotchas: docs/europeLogin/... (saved in memory as codemagic_new_app_runbook.md — also applies to AuditPic)
  • Maestro suite: .maestro/{auth,gallery,capture,verification,security,settings}/*.yaml — wired into .github/workflows/maestro-ci.yml
  • AuditPic backend port band: 8093 (workspace CLAUDE.md § Port Registry)

Reacties

Nog geen reacties