Repository navigation
Wayline: a full-stack ride-hailing sample, its CI and an Initializr template - #5984
shai-almog wants to merge 28 commits into
Conversation
…emplate scripts/wayline is one Maven project in one language: a Codename One app styled with CSS, and a Codename One Backend server. The role the server gives an account decides what it opens on: a rider's map, a driver's screen or an administrator's console, on a phone, on the desktop and hosted by the server itself in a browser. The server keeps its data in ORM entities behind repositories, with transactional services and Flyway-style migrations, and runs on SQLite, PostgreSQL, MySQL and MariaDB. It has sign-in through the built-in authorization server, phone verification, driver applications, matching, payments (simulated or Stripe), statistics and a live WebSocket channel. The app reports usage to Codename One analytics after consent. Tested like hellocodenameone: server tests on the JVM and as a native binary, simulator end-to-end tests with screenshots on phone and desktop, a headless-browser check of the hosted app, and a generated-project check (.github/workflows/wayline.yml). The Initializr offers it as a template, kept in step by scripts/sync-initializr-wayline.py, and the developer guide gains a user's and an implementor's chapter. Framework changes the sample needed or uncovered: - cn1:backend-webapp and the Gradle backendWebApp task build the app for the browser and let the server host it. - Shared-module contracts in an app reactor; ResponseStatusException; ConcurrencyFailureException for write conflicts and deadlocks, which MariaDB's snapshot isolation reports where other engines change no row. - Build-time weaving no longer exposes private types in generated code. - ParparVM: a receiver that escapes is no longer retired at frame exit. - Vector maps: tile queue with stand-ins, label collision grid, halos, road hierarchy, kinetic pan, zoom about the cursor. - JavaScript port: geolocation no longer blocks the EDT waiting for a position that never arrives; asynchronous XHR; coalesced accessibility refresh; released text layers. - JavaSE test runner retires each test's threads and listeners, and a killed test process is reported as such. - GridLayout preferred height counts implicit rows; GeneralPath grows geometrically; JavaSE mixed-font width uses advances. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Compared 12 screenshots: 12 matched. |
|
@codex review |
|
Developer Guide build artifacts are available for download from this workflow run:
Developer Guide quality checks: |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
Cloudflare Preview
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6794d2d704
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
Compared 206 screenshots: 206 matched. |
|
Compared 170 screenshots: 170 matched. Native Android coverage
✅ Native Android screenshot tests passed. Native Android coverage
Benchmark ResultsDetailed Performance Metrics
|
✅ Continuous Quality ReportTest & Coverage
Static Analysis
Generated automatically by the PR CI workflow. |
|
Compared 185 screenshots: 185 matched. Benchmark ResultsDetailed Performance Metrics
ParparVM vs HotSpot (JDK 25): Windows x64Runner CPU: AMD64 Family 25 Model 17 Stepping 1, AuthenticAMD (baseline 1 performance regression:
Ratios are ParparVM / JDK 25: below 1.00x ParparVM is faster (time) or smaller (RAM). Median of 5 interleaved, paired rounds; every run's output was verified. A ratio more than 15% (time) / 15% (RAM) away from its baseline in
A change that moves performance ON PURPOSE records the new baseline in Result: performance regression |
Gradle: a project in Java and Kotlin failed in compileJava with two copies of one generated mapper. Kotlin's pass compiles the Java it has not seen yet only to resolve types, and that output was read as a dependency's, so a @mapped Java class was mapped by both passes. AnnotationProcessing now takes the class directories that are the module's own and offers nothing out of them. wayline.yml: the simulator job runs in the pr-ci-container image and the workflow could not pull it without packages: read. Sample server: - A refund is refused while a tip on the ride is still being charged, so a tip can no longer land on a ride that was refunded without it. - A ride left completed with its payment pending is settled by a scheduled pass; settling is safe to repeat. - The card limit is enforced where a card is saved, not only where a setup starts. - Two registrations racing for one e-mail answer 409, not a server error. - Changing an account's roles closes the live channel it has open. Sample client: tokens are stored under a name made from the server's address, and cleared when the address changes, so one server's tokens are never sent to another. Maps: a map removed while gliding is taken off the form that animates it, and a failed tile is asked for again when its delay runs out, without waiting for something else to repaint the map. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Compared 185 screenshots: 185 matched. Benchmark ResultsDetailed Performance Metrics
ParparVM vs HotSpot (JDK 25): Windows arm64Runner CPU: ARMv8 (64-bit) Family 8 Model D49 Revision 0, MICROSOFT CORPORATION (baseline Ratios are ParparVM / JDK 25: below 1.00x ParparVM is faster (time) or smaller (RAM). Median of 5 interleaved, paired rounds; every run's output was verified. A ratio more than 15% (time) / 15% (RAM) away from its baseline in
Result: no regression |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
✅ ByteCodeTranslator Quality ReportTest & Coverage
Benchmark Results
Static Analysis
Generated automatically by the PR CI workflow. |
The vector map engine draws differently on this branch, so the four map screenshots are reseeded from this branch's CI captures. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ght up The JavaScript port on this branch brings the ARIA overlay up to date after the screen goes quiet rather than on every change, so a bounds read 150ms after a wheel event could still describe the list part way through the scroll, and the click then selected a different sample. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…S 27 map baselines build-ios-app.sh checked that MAVEN_HOME holds a Maven and then ran ./mvnw regardless, so the Wayline iOS job failed with 'No such file or directory'. It now uses the application's wrapper where there is one and that Maven otherwise, as build-android-app.sh does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Compared 163 screenshots: 163 matched. |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ed the macOS map baselines A name that follows a bend is drawn a straight stretch at a time. The stretches were laid out by each letter's width measured on its own, which a font with kerning sets wider than the same letters drawn together, so on iOS and Mac Catalyst a name read "Bro adway" where the road turned. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e18980f1b5
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
Compared 185 screenshots: 185 matched. Benchmark ResultsDetailed Performance Metrics
|
|
Compared 185 screenshots: 185 matched. ParparVM vs HotSpot (JDK 25): Linux x64Runner CPU: AMD EPYC 7763 64-Core Processor (baseline Ratios are ParparVM / JDK 25: below 1.00x ParparVM is faster (time) or smaller (RAM). Median of 5 interleaved, paired rounds; every run's output was verified. A ratio more than 15% (time) / 15% (RAM) away from its baseline in
Result: no regression |
|
Compared 185 screenshots: 185 matched. ParparVM vs HotSpot (JDK 25): Linux arm64Runner CPU: Neoverse-N2 (baseline 1 performance regression:
Ratios are ParparVM / JDK 25: below 1.00x ParparVM is faster (time) or smaller (RAM). Median of 5 interleaved, paired rounds; every run's output was verified. A ratio more than 15% (time) / 15% (RAM) away from its baseline in
A change that moves performance ON PURPOSE records the new baseline in Result: performance regression |
- A charge that fails without the processor saying whether it took the money leaves the ride pending and is asked for again under the same key; only a refused card is a failed payment. The same for a tip, which stays on the ride and can be sent again with the same amount. - A rider's two requests and two rides choosing one driver now take turns on the rider's and the driver's row, so neither ends in two rides. - The limit on guesses at a phone code is applied by the statement that counts the guess. - The driver role is not withdrawn from a driver who is on a ride. - A reconnect timer left over from before the live channel was restarted no longer opens a second connection. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…wo prose fixes The template check built the generated app with no display, and the theme compiler opens a window; it now takes a virtual display from xvfb-run on a Linux machine without one, as server.sh does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts: # scripts/initializr/common/src/test/java/com/codename1/initializr/model/GeneratorModelMatrixTest.java
# Conflicts: # maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/BackendPackageMojo.java
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Compared 168 screenshots: 168 matched. Benchmark Results
Build and Run Timing
Detailed Performance Metrics
|
|
Compared 168 screenshots: 168 matched. Benchmark Results
Build and Run Timing
Detailed Performance Metrics
|
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Compared 179 screenshots: 179 matched. Benchmark Results
Detailed Performance Metrics
ParparVM vs HotSpot (JDK 25): macOS arm64Runner CPU: Apple M1 (Virtual) (baseline Ratios are ParparVM / JDK 25: below 1.00x ParparVM is faster (time) or smaller (RAM). Median of 5 interleaved, paired rounds; every run's output was verified. A ratio more than 15% (time) / 15% (RAM) away from its baseline in
Result: no regression |
…ld build does, and one prose fix Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Compared 167 screenshots: 167 matched. Benchmark Results
Detailed Performance Metrics
|
# Conflicts: # scripts/initializr/common/src/main/resources/common.zip
The CSS compiler no longer opens a window, so the virtual display the template check, server.sh and the web job arranged for it goes, along with the designer jar the simulator's pom passed along. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@codex review |
…d retire proof Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1dc66ed703
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…ore review fixes - A refund the server claimed and never recorded is asked for again; the processor's refund is keyed by the charge, so a repeat is one refund. - A closed account's e-mail is retired (hash kept), since its rides stay filed under it and a re-registration would inherit them. - Role changes and blocks hold both profiles and re-read the acting admin, so two admins cannot remove each other at once. - A failed SMS send discards only its own code. - Closing an account asks for the password again. - /api/geo is rate limited. - Recent destinations belong to the account that chose them. - The location listener is removed when the last watcher leaves. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 92cdab1910
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
… nine more review fixes - Closing an account, removing a card, choosing the default card, keeping a first payment customer and sending a phone code hold the profile row, so each takes turns with a ride being asked for and with itself. - A guess at a phone code is claimed against the hash that was read. - A driver's status report holds the driver's row before reading it. - A card tip counts toward the balance once its charge is recorded. - A ride gives the rider's and the driver's usernames only to their owners and to an admin. - The app ignores profile answers that arrive after the session changed. - The staged web root is withheld only when the active profile, not any profile file, declares cn1.webapp.root. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
CodenameOne/CodenameOne/src/com/codename1/maps/vector/VectorMapEngine.java
Lines 952 to 954 in 3d3119e
When a vector tile is loaded, its label candidates are inserted into the unbounded labels map, while only the corresponding image is kept in the 256-entry rendered LRU. Panning across new regions therefore evicts rasterized tiles but retains every label list ever seen (including overzoom label sets), so a long map session continually grows memory and can eventually exhaust a mobile heap. Bound this data or remove its keys whenever the associated rendered tile or decoded parent is evicted.
CodenameOne/Ports/JavaScriptPort/src/main/webapp/js/localforage-shim.js
Lines 251 to 255 in 3d3119e
Every JavaScript-port storage write prints the first 60 characters of the serialized value, and the read path prints another prefix. Storage.writeObject() values reach this shim as byte arrays, so this base64 text is a reversible prefix of the original serialization; short stored strings can be exposed in full, and longer sensitive values such as the plain-fallback OIDC token document are partially disclosed in browser-console or captured diagnostic logs. Remove the value prefixes and log only non-sensitive metadata such as the key and length.
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| Long cents = session.createQuery("select coalesce(sum(r.fareCents), 0) from Ride r " | ||
| + "where r.driver = :driver and r.state = :completed " | ||
| + "and r.paymentStatus = :paid and r.updatedAt >= :since", Long.class) |
There was a problem hiding this comment.
Calculate dashboard earnings from the driver's share
For every paid ride with a nonzero commission, this query reports the rider's gross fareCents as the driver's Today/Week earnings in DriverForm, while the detailed earnings screen and cash-out balance use driverCents. The main driver dashboard therefore displays more money than the driver actually earned or can withdraw; sum the driver's share, plus only any settled tip if that endpoint is intended to include tips.
Useful? React with 👍 / 👎.
| for (int iter = 0; iter < rides.size(); iter++) { | ||
| Ride ride = rides.get(iter); | ||
| long at = ride.updatedAt; | ||
| long earned = ride.driverCents + ride.tipCents; |
There was a problem hiding this comment.
Exclude unsettled tips from period earnings
When a tip charge ends with an ambiguous IOException, the ride deliberately retains tipCents while no Payment.tipRef exists. Although the current PayoutRepository.tips() fix excludes that amount from tips and the cash-out balance, this loop still adds it to Today, Week, Month, and the daily chart, so the detailed earnings screen claims the driver earned money that may never have been charged. Apply the same settled-card-tip predicate here while continuing to include cash tips.
Useful? React with 👍 / 👎.
| if (retryPending) { | ||
| return; |
There was a problem hiding this comment.
Reschedule retries when an earlier tile deadline appears
When a timer is already pending for a repeatedly failing tile with a long backoff, a newly failed visible tile reaches this return even though its first retry is due sooner. The sole timer may be waiting for up to 60 seconds, so the new hole ignores its configured 2-second retry until that unrelated deadline fires. Track the scheduled deadline and replace or supplement the timer whenever wait is earlier.
Useful? React with 👍 / 👎.
| # What the hosted web app runs on: the browser side of the JavaScript | ||
| # port, which no test here reached before the `web` job. | ||
| - 'Ports/JavaScriptPort/src/main/webapp/**' |
There was a problem hiding this comment.
Trigger the hosted-web job for JavaScript port sources
In the inspected wayline.yml pull-request filter, only Ports/JavaScriptPort/src/main/webapp/** triggers this workflow, even though the hosted app also compiles and runs src/main/java implementations such as NetworkConnection and HTML5Implementation. A future PR changing those classes will therefore skip Wayline's only full hosted-app sign-in test despite the workflow comment saying this path covers the browser side; include the Java source tree, or the whole JavaScript port, in this filter.
Useful? React with 👍 / 👎.
| int month = (text.charAt(5) - '0') * 10 + (text.charAt(6) - '0'); | ||
| int day = (text.charAt(8) - '0') * 10 + (text.charAt(9) - '0'); | ||
| return month >= 1 && month <= 12 && day >= 1 && day <= 31; |
There was a problem hiding this comment.
Validate the day against its actual month
For any driver application date whose day is 29–31, this check accepts it solely because the day is at most 31, even when that date cannot exist, such as 2026-02-31 or 2025-04-31. Applications.date() relies on this method for both date of birth and licence expiry and then compares the strings without parsing them, so invalid identity and licence dates can be submitted and approved. Check month lengths and February's leap-year rule before accepting the value.
Useful? React with 👍 / 👎.
| PayoutDto paid = pay(driver); | ||
| if (takeBackIfOverdrawn(driver, paid.id)) { | ||
| throw new ResponseStatusException(409, "There is nothing to cash out"); |
There was a problem hiding this comment.
Serialize concurrent cash-outs before writing the ledger
When two cash-out requests for one driver both commit their payout rows before either reaches this check, both see the shared balance as overdrawn and each deletes its own row. Both requests then return 409 and no payout remains even though the original positive balance is still present, contradicting the intended behavior that only one request is taken back. Serialize the operation on a stable per-driver row, or atomically claim the available balance before creating the payout.
Useful? React with 👍 / 👎.
What this is
scripts/waylineis a modern successor to the ride-hailing app of "Create an Uber clone in 14 days": one Maven project in one language, a Codename One app styled with CSS and a Codename One Backend server. The roles the server gives an account decide what it opens on: a rider's map, a driver's screen or an administrator's console. It runs on phones, as a desktop app, and hosted by its own server in a browser.@Transactionalservices, Flyway-style migrations (per-engine variants where the SQL differs), matching, a ride state machine that settles races in the database, simulated or Stripe payments, a WebSocket live channel.scripts/sync-initializr-wayline.py(CI fails on drift). The grub and tweet templates are removed.Framework changes the sample needed or uncovered
cn1:backend-webappand the GradlebackendWebApptask: build the app for the browser and let the server host it.ResponseStatusException;ConcurrencyFailureExceptionfor write conflicts and deadlocks (MariaDB's snapshot isolation reports error 1020 where other engines change no row).FrameRetireLiveReceiverIntegrationTest).GridLayoutpreferred height counts implicit rows;GeneralPathgrows geometrically; JavaSE mixed-font width uses advances.Testing
Run locally on the merged tree:
scripts/wayline/screenshots.run-web-e2e.shin headless Chromium.Not verified:
.github/workflows/wayline.ymlhas never run on GitHub.🤖 Generated with Claude Code