docs mobile p23 city community feed - AlexandreZanata/Abastevo GitHub Wiki
City community feed — bounded user-requested extension
Task: P23-CITY-FEED / issue #123 (2026-10-06), related to P23-T01 and P20 discovery. Base: a6a8493. Branch: codex/phase-23-city-community-feed. This request authorizes the city feed, not follows, notifications, a public pilot or complete P23 acceptance.
Behavior contract recorded before implementation
- B-BR-C07: anonymous city activity reads require the canonical seven-digit IBGE municipality and UF. Only active stations in that exact city are included. This is a logical city boundary inside the existing modular monolith, not a tenant or another service.
- B-BR-C08: feed cards represent current AVAILABLE community projections, not unvalidated submissions or official substitutes. Expiry is checked at read time independently of the worker. Source, fuel, exact integer BRL price, unit, STANDARD sale condition and update dates remain explicit; expiry stays explicit in the protocol and is enforced by server and client. No contributor identity, private coordinates, evidence/storage URL or image is public.
- B-BR-C09: recent order is descending anchor time with station UUID tie-break; cheapest order is integer amount ascending then station UUID. One selected fuel and its canonical unit are mandatory; only STANDARD/ STANDARD qualifier prices are compared. HMAC cursors bind city, fuel, order and page size; refresh replaces the first page, pagination is bounded. Concurrent projection changes can move rows between live pages; the client deduplicates and resets pagination on refresh.
- B-BR-C10: automatic updates use a 15-second foreground refresh, cancelled when the screen is stopped; no background GPS, notification permission or account is necessary. This is near-real-time refresh after existing validation/consensus processing, not an instantaneous submission guarantee. Failed refresh retains same-city cards with an explicit error/stale indication; changing city/fuel/order clears unrelated data. Expired cards disappear locally too.
- BUC-C06: GIVEN a preferred city, WHEN opening Community, THEN show that city's selected-fuel feed and a city selector, contribution entry, recent/cheapest filters and dated community cards. No data shows a useful empty state, never fabricated people or prices. Contribution enters existing station selection; card detail opens the canonical station profile. Rules remain accessible.
- BUC-C07: GIVEN foreground feed, WHEN a validated projection changes, THEN the newest page is automatically refreshed without duplicate cards; while browsing older pages, new updates are offered through an explicit refresh action to preserve scroll position. WHEN leaving the screen, THEN stop refresh; WHEN city changes, THEN cancel old work and load the new scope.
Selected validation
Backend: pure filter/cursor tests; anonymous HTTP invalid filters, changed/tampered/expired cursors, failure redaction and privacy allowlist; real PostGIS city isolation, expiry, disputed/nonstandard exclusion, money order, stable pagination and concurrent reads/writes. sqlc generation/vet, backend build/vet/staticcheck and OpenAPI lint. Append-only index migration with fresh/upgrade/idempotent migration tests. Android: transport/codec validation, foreground refresh/cancellation/city switch/error preservation tests; Compose content/empty/error/filter/large-font checks on the identified Poco; APK build/lint. Diff and secret-surface review. No production deployment or trust bypass.
Owned SQL boundary
Community owns the feed query and its generated package. It reads only directory_stations.id/display_name/municipality_code/state/status (canonical public station fields) to scope the existing community projection; it never imports the directory module or its generated package. These schema migrations are already explicitly listed in the community sqlc stanza. The read-only join is additive, parameterized and indexed; it does not change either module's write ownership. Directory's existing municipality index is reused. A rebuildable partial projection index supports each feed order. No new runtime dependency.
Status: LOCAL_DONE Validation: PASS
Local source / Android acceptance
Tested behavior is the working tree based on a6a8493, identified by the 41-file SHA-256 source manifest. Manifest SHA-256: 26eb657bc18cd277381762fe0a94c15102e26585378da4e416beeeba631e3b3d. This is task acceptance / INTEGRATION_PENDING, not complete P23/G23, deployment, merge or production certification.
- Backend RED recorded: the first
go test .../application -run TestFeedfailed because ValidateFeed/FeedKey did not exist. Implemented the pure contract and obtained GREEN. go test -race -count=1 ./internal/modules/community/application ./internal/modules/community/adapters/read ./internal/modules/community/adapters/http ./internal/platform/apicontract: PASS, including exact fuel vocabulary, invalid filters/cursors, unsigned public reads, outage redaction and private-field exclusion.go test -race -count=1 -tags=integration ./internal/modules/community/adapters/read ./internal/modules/community/adapters/http ./internal/platform/migrate ./internal/platform/apicontract: PASS on real local PostGIS. Each fixture creates/drops its own unique database on the local development server. Proved city separation, inactive stations, disputed/nonstandard/expired exclusion, same-fuel integer ordering, tie-break pagination, immediate visibility of committed concurrent updates, query-time expiry without a worker, fresh migrations, upgrade preserving 3981-milli facts/old reads, idempotent and concurrent migrations.ANPFUEL_TEST_DATABASE_URL=... go test -race -count=1 -tags=integration ./cmd/api -run TestPublicProcessIdentityAndSignedWrites -timeout 120s: PASS (7.278s). Actual child API process mounts the new unsigned feed and preserves signed-write/identity regression behavior. No live provider/private S3 acceptance is claimed.bash scripts/check-backend-fast.sh: PASS (build/vet/unit/staticcheck/sqlc/OpenAPI/secret gates). It initially exposed inherited formatting in two tests, two unused private helpers and one test self-assignment. Fixed only these gate failures without changing behavior. Final new integration tests/import grouping then passed scopedstaticcheck -tags integration,go vet -tags integration,sqlc vet,sqlc diff, affected unit tests andgo build ./cmd/api. OpenAPI lint: PASS, 58 warnings/33 informs; none suppressed.- Android scoped JVM checks:
:application:test --tests '*GetCityCommunityFeedUseCaseTest'2/2;:data:testDebugUnitTest --tests '*CityCommunityFeedHttpClientTest'5/5;:app:testDebugUnitTest --tests '*CommunityFeedViewModelTest'8/8. Proved canonical manual city resolution, no invented codes/GPS/network during resolution, integer money and additive-fuel bridge, cross-city/source/unit/condition refusal, actual HTTP cancellation, bounded/malformed JSON, 15-second foreground updates and stop, filters/city cancellation, failed-refresh preservation, local expiry, duplicate pagination, city-selection recovery and stable older-page browsing/new-update application. :app:assembleDebug,:app:assembleDebugAndroidTest,:app:lintDebug: PASS. Lint has 0 errors / 179 warnings; all existing eight languages include feed strings. No dependency addition. Feed calls use existing HTTPS transport, no redirects/retries, 12-second total timeout and cancellation; body limit 256 KiB / bounded nesting.:app:assembleReleaseand:app:verifyReleaseApkSize: PASS. Unsigned release APK 3,123,082 bytes (below 15 MiB), SHA-256595cab36b6b24fe26135349ea2934f422f79ddae7a2101e1860bdd1c75eed92a; build only, not distribution/certification.- Identified Poco
VKCQGAUCGYAMR4W4, model 2311DRK48G, Android 16/API36:install -rpreserved app data; actualCommunityFeedScreenTest4/4 passed. Light/dark, exact 3.981-milli formatting, station/contribution routes, empty coverage, connection failure with retained cards, city/fuel/sort selectors and 2x font. Test screenshots use only synthetic station/price fixtures and capture Compose root; device notification images are not committed. No tablet/emulator operation. - Final debug APK SHA-256:
ceb6e3184f70d3c5b6cbb5870536f8172aacda71e7d4f4cad1afcd0eb8880924; instrument APK:308aa5a5b2ab75e8f0d74d935446e22a911219503137238a2218aece725b1a42. Final phone build is this artifact; current city preference is retained. - Pages are manual and capped at 200 displayed prices, with explicit previously-loaded wording while browsing older pages. Automatic refresh follows the newest page; new facts do not move old cards under the reader. Explicit refresh resets pagination, and a failed refresh retains same-city rows. Confidence is a dated consensus signal, never an ANP badge or truth guarantee.
Runtime / delivery limit
Actual curl to https://teste.abastevo.com.br/v1/community/feed?... failed certificate verification (exit 60 / HTTP 000). Actual app showed its honest connection-failure state; it contains no fabricated feed. Staging trust and rollout of this additive endpoint/migration remain INTEGRATION_PENDING. No TLS bypass, device CA installation, production changes, notifications/follows, per-city services, PR/merge or release tag. Existing broader batch/runtime blockers remain unchanged.
Authorized delivery: reuse milestone 17 and issue #123, atomic task commit and branch backup push; keep issue open until cumulative integration under ADR-018. Recovery is reverting the additive consumer/route; the rebuildable indexes leave old reads and price facts intact. Next runtime action: resolve trusted staging connectivity and deploy the reviewed API/migration under the project's deployment authorization, then verify a real city feed without changing source/privacy semantics.