Skip to content

Mobile API: public GET /auth/registration-fields for configurable/custom signup fields (#255)#277

Merged
fabiodalez-dev merged 3 commits into
mainfrom
feat/255-mobile-registration-fields
Jul 21, 2026
Merged

Mobile API: public GET /auth/registration-fields for configurable/custom signup fields (#255)#277
fabiodalez-dev merged 3 commits into
mainfrom
feat/255-mobile-registration-fields

Conversation

@fabiodalez-dev

@fabiodalez-dev fabiodalez-dev commented Jul 21, 2026

Copy link
Copy Markdown
Owner

Adds the missing discovery endpoint so the Android app (and any client) can render the registration form for #255's configurable + custom fields.

Why

POST /auth/register already validates custom fields and GET /me returns them for logged-in users, but there was no public endpoint exposing the field schema before signup — so a client couldn't know which built-in fields are required on this instance or which admin-defined custom fields to show.

Endpoint

GET /api/v1/auth/registration-fields — public (no token), gated on the same app-access flag as the other auth endpoints. Returns:

  • registration_enabled — lets the client distinguish "app disabled" from "signup closed"
  • builtin_fields — the three config-driven toggles (cognome/telefono/indirizzo), each { required: isRequired(key), configurable: true }
  • custom_fieldsRegistrationFields::apiDefinitions(): active fields only, { id, label, type, required }, ordered, leaking no attivo/ordine

data_nascita/cod_fiscale/sesso are intentionally not in the signup contract (register() never reads them; profile-only, via GET/PATCH /me).

Implementation

Reuses existing RegistrationFields::{BUILTIN_TOGGLES, isRequired, apiDefinitions} — no new controller file. OpenAPI spec + mobile-api-idempotency manifest test updated; mobile-api plugin 1.3.0 → 1.4.0.

Verified (live, on the dev install)

  • GET returns 200 with the correct {data, meta, error} envelope.
  • builtin_fields reflects the real isRequired() config.
  • custom_fields reflects apiDefinitions() dynamically — seeded a field → it appeared, deleted it → gone.
  • php -l + PHPStan level 5 clean; route ↔ OpenAPI ↔ manifest consistent.

The matching Android client work (models, PinakesApi, dynamic register/profile fields) is in a separate PR on the Pinakes-Android repo.

Summary by CodeRabbit

  • Nuove funzionalità

    • Aggiunto un endpoint pubblico per scoprire i campi disponibili durante la registrazione.
    • Ora sono indicati campi integrati, campi personalizzati, obbligatorietà e stato della registrazione.
    • L’endpoint è documentato nell’API ed è soggetto a limitazione delle richieste.
  • Correzioni

    • Gestiti gli errori di accesso, le richieste eccessive e gli errori interni con risposte appropriate.
  • Manutenzione

    • Aggiornata la versione del componente Mobile API alla 1.4.0.

…e app

The Mobile API validated custom registration fields (POST /auth/register) and
returned them for logged-in users (GET /me), but had no public discovery
endpoint — a client had no way to learn, before signup, which built-in fields
are required on this instance or which admin-defined custom fields to render.

Add public GET /api/v1/auth/registration-fields (no token, gated on the same
app-access flag as the other auth endpoints). Returns:
  - registration_enabled (client tells "app disabled" from "signup closed")
  - builtin_fields: the three config-driven toggles (cognome/telefono/indirizzo)
    each { required: isRequired(key), configurable: true }
  - custom_fields: RegistrationFields::apiDefinitions() — active only,
    { id, label, type, required }, ordered, leaking no attivo/ordine.

data_nascita/cod_fiscale/sesso are intentionally NOT in the signup contract:
register() never reads them; they are profile-only, editable via GET/PATCH /me.

Reuses existing RegistrationFields::{BUILTIN_TOGGLES, isRequired, apiDefinitions}
— no new src file. OpenAPI + manifest test updated; mobile-api 1.3.0 -> 1.4.0.

Verified live: GET returns 200 with the correct envelope; builtins reflect the
real isRequired() config, custom_fields dynamically reflect apiDefinitions()
(seeded a field -> appeared, deleted -> gone). php -l + PHPStan level 5 clean.
@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@fabiodalez-dev, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 47 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: b9b108bc-d3e7-4e16-baf8-72745a7789bc

📥 Commits

Reviewing files that changed from the base of the PR and between 92c5bb1 and cb709a6.

📒 Files selected for processing (4)
  • storage/plugins/mobile-api/src/Controllers/AuthController.php
  • storage/plugins/mobile-api/src/Controllers/HealthController.php
  • storage/plugins/mobile-api/src/Controllers/OpenApiController.php
  • tests/mobile-api.spec.js
📝 Walkthrough

Walkthrough

Aggiunge un endpoint pubblico Mobile API per scoprire i campi di registrazione, con controllo dell’accesso, rate limiting, payload documentato in OpenAPI, aggiornamento della versione del plugin e verifica nei test di idempotenza.

Changes

Discovery registrazione mobile

Layer / File(s) Summary
Contratto OpenAPI
storage/plugins/mobile-api/src/Controllers/OpenApiController.php
Documenta GET /auth/registration-fields, lo schema RegistrationFieldsPayload e le risposte 200, 403, 429 e 500.
Endpoint e validazione
storage/plugins/mobile-api/src/Controllers/AuthController.php, storage/plugins/mobile-api/MobileApiPlugin.php, storage/plugins/mobile-api/plugin.json, tests/mobile-api-idempotency.spec.js
Collega la rotta pubblica alla nuova action, applica il rate limit dedicato, espone i campi builtin e custom, aggiorna la versione a 1.4.0 e include l’endpoint nei test di idempotenza.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed Il titolo riassume chiaramente l'aggiunta dell'endpoint pubblico per i campi di registrazione configurabili e custom.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/255-mobile-registration-fields

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@fabiodalez-dev

Copy link
Copy Markdown
Owner Author

🔎 Adams Review — PR #277 (mobile registration-fields)

Adversarial multi-lens pass (correctness / structural blast-radius / security). Endpoint is correct, safe, and well-scoped — but the structural lens surfaced a real redundancy worth deciding on before merge.

⚠️ Confirmed — duplicate public source of truth for the registration contract

The public GET /api/v1/health endpoint already returns the same registration-discovery data this PR adds, just in a divergent shape:

/health (existing) /auth/registration-fields (this PR)
enabled flag registration_enabled registration_enabled
built-in required registration.require_cognome / require_telefono / require_indirizzo (flat booleans) builtin_fields.<field>.{required, configurable} (nested)
custom fields registration.custom_fields = apiDefinitions() custom_fields = apiDefinitions()

So a client now has two public ways to learn the same signup contract, in two shapes it must reconcile. HealthController.php:93-97.

Decide one of:

  • Drop the new endpoint, have the Android register screen read the registration block from /health (it already calls /health on startup) — smallest surface.
  • Keep it (a dedicated, purpose-named endpoint is arguably cleaner for the register screen) but consider deprecating the registration block in /health, or at least documenting that the two are intentional and which is canonical.

Not a bug — but two public contracts for one thing tends to drift. Your call.

ℹ️ Minor — discovery payload omits the always-required core fields

register() unconditionally requires nome/email/password, but the discovery payload advertises cognome (in builtin_fields) and the custom fields, not nome/email/password. A client rendering the form purely from this contract could omit nome. In practice every client hardcodes name/email/password, so this is low — but a one-line note in the payload or docs ("core fields nome/email/password are always required and not listed here") would close the gap. AuthController.php:355.

✅ Clean

  • Security (L6): public + no-token is intentional and safe — schema-only disclosure equivalent to the public /registrati web page; no PII/user values, apiDefinitions() correctly hides attivo/ordine, same app-access 403 gate as the other public auth endpoints, rate-limited 30/300s.
  • Correctness (L1): the one flagged item — manifest row kind:'doc' asserting HTTP 200 while the handler can 403 — is a false positive: the test harness seeds mobile_api.enabled=1 (mobile-api-idempotency.spec.js:86), so the endpoint always returns 200 under test.
  • Route correctly public inside /api/v1, envelope matches ResponseEnvelope::success, required flags can't drift from register() (both call isRequired()), OpenAPI ↔ route ↔ manifest consistent.

Lenses: L1 diff-local, L2 structural, L6 security. Findings verified against the code, not just flagged.

…health

Adams-review follow-ups on the registration-fields endpoint:

- Minor finding: the discovery payload advertised the configurable toggles
  (cognome/telefono/indirizzo) and custom fields but NOT nome/email/password,
  which register() requires unconditionally — a client rendering purely from
  the contract could omit `nome`. Now builtin_fields carries the three core
  fields with {required:true, configurable:false}, so the contract is
  self-complete and a client can tell mandatory-fixed from configurable.
  (password_confirm stays a client-side echo, not advertised.)

- Structural finding (two public sources of truth): /health also carries a
  registration summary. It shipped in 0.7.37 and has an existing client field
  + test, so removing it would be a breaking change to a public API — worse
  than the redundancy. Both derive from the same RegistrationFields source, so
  values cannot drift. Documented the relationship in both controllers + the
  OpenAPI description: /auth/registration-fields is the canonical form-render
  contract, /health carries a lightweight mirror.

Verified live: builtin_fields now returns nome/email/password (configurable
false) + the three toggles; PHPStan level 5 clean.
…tests: envelope, core fields, toggles, no profile-leak, custom-field shape, public)
@fabiodalez-dev
fabiodalez-dev merged commit 33e9176 into main Jul 21, 2026
5 of 6 checks passed
@fabiodalez-dev
fabiodalez-dev deleted the feat/255-mobile-registration-fields branch July 21, 2026 21:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant