Add shared authentication and email verification services

Provide reusable models, injectable service contracts, lifecycle-safe providers and explicit dummy implementations for login, signup and verification. Add focused error and async lifecycle tests. Related to #4 and #5.
This commit is contained in:
Stephan D committed 2026-09-11 15:36:58 +02:00
1 parent d9318053e8
commit 27424ed886
15 files changed
+708

No files matched your search

+63
View File
@@ -0,0 +1,63 @@
# sxchnge_auth
Shared Flutter authentication providers and service contracts for web and mobile. Private package, version 0.1.0; Flutter 3.47+ / Dart 3.13+.
## Install and use
From `frontend/app` (or a sibling `frontend/mobile` app):
```yaml
dependencies:
sxchnge_auth:
path: ../packages/sxchnge_auth
```
```dart
import 'package:sxchnge_auth/sxchnge_auth.dart';
final login = LoginProvider(const DummyLoginService());
login.addListener(() {
// Render login.state.status, result, or typed error in your own UI.
});
await login.login(
email: 'demo@example.com',
password: 'example-password',
locale: 'en',
);
login.dispose();
```
`SignupProvider` accepts a `SignupService` and exposes `signup(name:, email:, password:, locale:)`. Both providers extend ChangeNotifier and can be installed with `ChangeNotifierProvider`, ListenableBuilder, or another Flutter state binding. The package itself depends only on Flutter foundation; it contains no widgets, routes, localization, web-only code, network client, or storage.
## Lifecycle and services
Providers expose immutable `AuthState`: idle, loading, success, or error. They trim email/name, preserve the password verbatim, pass the locale to services, suppress duplicate submissions while loading, and clear old errors before retrying. Reset invalidates older responses and allows a new request; disposal ignores all later completions. Reset does not cancel remote work. Do not treat a provider reset as undoing a production signup.
Services return `AuthResult` or throw `AuthException` with a typed `AuthError`. Unexpected exceptions are reduced to `unexpected`; raw errors and credentials are not retained in provider state. Credentials exist only as ephemeral request input. Localize error codes in each consuming application.
`DummyLoginService` and `DummySignupService` default to 600ms latency and simulated success. They do not validate credentials against an account registry, create accounts, issue tokens, open sessions, send requests, or persist data. Configure errors explicitly:
```dart
final service = DummyLoginService(
delay: Duration.zero,
failure: AuthError.invalidCredentials,
);
```
Supported failure codes: `invalidCredentials`, `emailInUse`, `unavailable`, and `unexpected`. Inject another implementation for deterministic retry scenarios or production integration. `AuthResult.isSimulated` distinguishes dummy responses; a successful operation alone must never be treated as an authorization decision. The package does not implement authenticated application/session state yet.
## Sendico reuse
Adapted the ChangeNotifier lifecycle, service separation, locale-carrying request, and typed-outcome patterns from Sendico's `pshared/lib/provider/account.dart`, `models/auth/login_outcome.dart`, and `service/authorization/client.dart`. These were patterns rather than directly portable implementations: the originals depend on Sendico account/organization models, device IDs, static API services, token storage, and verification flows. Those dependencies are deliberately absent here. The B2B organization signup contract is not copied into the consumer product.
When a supported sxchnge BFF contract exists, implement transport DTOs and mappers behind the service interfaces, returning domain results. No dummy DTO/mapping layer is needed without serialized transport. Keep web cookie and mobile credential handling in production platform adapters, not the providers.
## Validation
`flutter analyze` and `flutter test` from this directory; `make test-frontend` from the repository root also runs all consuming app and theme tests. Tests cover duplicate submission, request forwarding, typed/unexpected failures, retry, reset races, disposal, and both dummy implementations.
## Email verification
`VerificationService` exposes `send(email, locale)` and `confirm(token)` as named-argument methods. Inject an implementation into `VerificationProvider`, shared by web and mobile. The provider exposes immutable `VerificationState` (idle/sending/sent/checking/verified/expired/invalid/error), suppresses concurrent duplicate operations, and ignores completions after reset or disposal. Typed `VerificationException` maps confirmation failures; unknown exceptions become internal errors without exposing exception text. Sending failures always become the general error state.
`DummyVerificationService` supports `demo-valid`, `demo-expired`, and `demo-internal` confirmation tokens; other tokens are invalid. Configure `delay` and `sendFailure` for tests. Results are explicitly simulated. It performs no network, storage, mail delivery, or account mutation. A production adapter must implement backend validation, delivery, rate limits, and safe token handling; this client provider is not an authorization boundary.