Initial commit: Flutter app + PHP/MySQL backend on Hostinger

Replaces Firebase with a self-hosted PHP/MySQL API served from
winded.prymsolutions.com. Includes full backend (schema, auth, events,
teams, brackets, suggestions, stats, media, file upload) and updated
Flutter repositories and domain models.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-14 20:13:57 -07:00
commit b239ae3e5f
208 changed files with 19187 additions and 0 deletions
@@ -0,0 +1,38 @@
import 'package:riverpod_annotation/riverpod_annotation.dart';
import '../../auth/application/auth_notifier.dart';
import '../../../core/admin/admin_guard.dart';
import '../domain/user_profile.dart';
import '../infrastructure/profile_repository.dart';
part 'profile_notifier.g.dart';
/// Live profile of the currently signed-in user. Emits null while loading or
/// when no user is signed in.
@riverpod
Stream<UserProfile?> currentProfile(CurrentProfileRef ref) {
final user = ref.watch(authNotifierProvider).valueOrNull;
if (user == null) return Stream.value(null);
return ref.watch(profileRepositoryProvider).watchProfile(user.uid);
}
/// Resolves the effective [UserRole] for the current session. Admin status is
/// determined by email allow-list first (so seed-data admins work before
/// they've even loaded a profile doc); otherwise the Firestore-stored role is
/// used, defaulting to [UserRole.viewer] when not logged in.
@riverpod
UserRole currentUserRole(CurrentUserRoleRef ref) {
final user = ref.watch(authNotifierProvider).valueOrNull;
if (user == null) return UserRole.viewer;
if (isAdmin(user)) return UserRole.admin;
final profile = ref.watch(currentProfileProvider).valueOrNull;
if (profile == null) return UserRole.viewer;
return profile.role;
}
/// One-shot lookup of an arbitrary user profile by uid. Used by the public
/// player profile screen.
@riverpod
Future<UserProfile?> profileById(ProfileByIdRef ref, String uid) {
return ref.watch(profileRepositoryProvider).getProfile(uid);
}