Initial commit: Uruk Prize Platform architecture, backend core, mobile app, gateway caller & deployment pipeline

This commit is contained in:
Hamza-Ayed
2026-09-18 17:12:05 +03:00
commit 879dd36f1b
1149 changed files with 97122 additions and 0 deletions
@@ -0,0 +1,104 @@
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../../core/network/api_client.dart';
import '../../../core/security/fingerprint_service.dart';
import 'auth_state.dart';
class AuthCubit extends Cubit<AuthState> {
final ApiClient _apiClient;
final FingerprintService _fingerprintService;
AuthCubit({
ApiClient? apiClient,
FingerprintService? fingerprintService,
}) : _apiClient = apiClient ?? ApiClient(),
_fingerprintService = fingerprintService ?? FingerprintService(),
super(AuthInitial());
Future<void> checkExistingSession() async {
try {
final token = await _fingerprintService.getSessionToken();
final userId = await _fingerprintService.getUserId();
final fingerprint = await _fingerprintService.getDeviceFingerprint();
if (token != null && userId != null) {
emit(Authenticated(
user: {'id': userId, 'full_name': 'عضو أوروك'},
token: token,
deviceFingerprint: fingerprint,
));
} else {
emit(Unauthenticated());
}
} catch (_) {
emit(Unauthenticated());
}
}
Future<void> requestOtp(String phone) async {
emit(AuthLoading());
try {
final response = await _apiClient.post(
'/api/v1/auth/request-otp',
body: {'phone': phone},
requiresAuth: false,
);
final data = response['data'] as Map<String, dynamic>?;
emit(AuthOtpSent(
phone: phone,
mockOtp: data?['mock_otp'] as String?,
));
} catch (e) {
emit(AuthFailure(e.toString()));
}
}
Future<void> verifyOtpAndBindDevice({
required String phone,
required String otp,
String? fullName,
}) async {
emit(AuthLoading());
try {
final fingerprint = await _fingerprintService.getDeviceFingerprint();
final model = await _fingerprintService.getDeviceModel();
final response = await _apiClient.post(
'/api/v1/auth/verify-otp',
body: {
'phone': phone,
'otp': otp,
'device_fingerprint': fingerprint,
'device_model': model,
if (fullName != null && fullName.isNotEmpty) 'full_name': fullName,
},
requiresAuth: false,
);
final data = response['data'] as Map<String, dynamic>;
final user = data['user'] as Map<String, dynamic>;
final token = data['token'] as String;
final secret = data['device_secret'] as String;
final userId = user['id'] as int;
await _fingerprintService.saveAuthSession(
userId: userId,
token: token,
deviceSecret: secret,
);
emit(Authenticated(
user: user,
token: token,
deviceFingerprint: fingerprint,
));
} catch (e) {
emit(AuthFailure(e.toString()));
}
}
Future<void> logout() async {
await _fingerprintService.clearSession();
emit(Unauthenticated());
}
}
@@ -0,0 +1,48 @@
import 'package:equatable/equatable.dart';
abstract class AuthState extends Equatable {
const AuthState();
@override
List<Object?> get props => [];
}
class AuthInitial extends AuthState {}
class AuthLoading extends AuthState {}
class AuthOtpSent extends AuthState {
final String phone;
final String? mockOtp;
const AuthOtpSent({required this.phone, this.mockOtp});
@override
List<Object?> get props => [phone, mockOtp];
}
class Authenticated extends AuthState {
final Map<String, dynamic> user;
final String token;
final String deviceFingerprint;
const Authenticated({
required this.user,
required this.token,
required this.deviceFingerprint,
});
@override
List<Object?> get props => [user, token, deviceFingerprint];
}
class Unauthenticated extends AuthState {}
class AuthFailure extends AuthState {
final String errorMessage;
const AuthFailure(this.errorMessage);
@override
List<Object?> get props => [errorMessage];
}