Initial scaffold: FocusFlow ADHD Task Manager backend
Dart Shelf API with modules: auth (JWT + PBKDF2), tasks (CRUD + dopamine scorer), streaks (forgiveness + freeze), rewards (variable reward engine), time perception, sync (offline-first push/pull), rooms (body doubling placeholder). Includes DB migration (001_initial_schema.sql) and Docker Compose. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
98
lib/src/modules/streaks/streak_routes.dart
Normal file
98
lib/src/modules/streaks/streak_routes.dart
Normal file
@@ -0,0 +1,98 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:shelf/shelf.dart';
|
||||
import 'package:shelf_router/shelf_router.dart';
|
||||
|
||||
import '../../middleware/error_handler.dart';
|
||||
import '../../shared/api_response.dart';
|
||||
import 'streak_service.dart';
|
||||
|
||||
/// Streak module route definitions.
|
||||
class StreakRoutes {
|
||||
final StreakService _service;
|
||||
|
||||
StreakRoutes(this._service);
|
||||
|
||||
Router get router {
|
||||
final router = Router();
|
||||
|
||||
router.get('/', _listStreaks);
|
||||
router.post('/', _createStreak);
|
||||
router.get('/<id>', _getStreak);
|
||||
router.post('/<id>/complete', _completeToday);
|
||||
router.post('/<id>/forgive', _forgive);
|
||||
router.post('/<id>/freeze', _freeze);
|
||||
router.get('/<id>/history', _getHistory);
|
||||
|
||||
return router;
|
||||
}
|
||||
|
||||
// ── Handlers ────────────────────────────────────────────────────────
|
||||
|
||||
Future<Response> _listStreaks(Request request) async {
|
||||
final userId = request.context['userId'] as String;
|
||||
final streaks = await _service.listStreaks(userId);
|
||||
return ApiResponse.success(streaks);
|
||||
}
|
||||
|
||||
Future<Response> _createStreak(Request request) async {
|
||||
final userId = request.context['userId'] as String;
|
||||
final body =
|
||||
jsonDecode(await request.readAsString()) as Map<String, dynamic>;
|
||||
|
||||
if (body['name'] == null || (body['name'] as String).isEmpty) {
|
||||
throw ApiException.badRequest('Name is required');
|
||||
}
|
||||
|
||||
final streak = await _service.createStreak(userId, body);
|
||||
return ApiResponse.created(streak);
|
||||
}
|
||||
|
||||
Future<Response> _getStreak(Request request, String id) async {
|
||||
final userId = request.context['userId'] as String;
|
||||
final streak = await _service.getStreak(id, userId);
|
||||
return ApiResponse.success(streak);
|
||||
}
|
||||
|
||||
Future<Response> _completeToday(Request request, String id) async {
|
||||
final userId = request.context['userId'] as String;
|
||||
final result = await _service.completeToday(id, userId);
|
||||
return ApiResponse.success(result, message: result['message'] as String);
|
||||
}
|
||||
|
||||
Future<Response> _forgive(Request request, String id) async {
|
||||
final userId = request.context['userId'] as String;
|
||||
|
||||
String? note;
|
||||
try {
|
||||
final body =
|
||||
jsonDecode(await request.readAsString()) as Map<String, dynamic>;
|
||||
note = body['note'] as String?;
|
||||
} catch (_) {
|
||||
// body optional
|
||||
}
|
||||
|
||||
final result = await _service.forgive(id, userId, note: note);
|
||||
return ApiResponse.success(result, message: result['message'] as String);
|
||||
}
|
||||
|
||||
Future<Response> _freeze(Request request, String id) async {
|
||||
final userId = request.context['userId'] as String;
|
||||
final body =
|
||||
jsonDecode(await request.readAsString()) as Map<String, dynamic>;
|
||||
|
||||
final days = body['days'] as int?;
|
||||
if (days == null) {
|
||||
throw ApiException.badRequest('Field "days" is required');
|
||||
}
|
||||
|
||||
final result = await _service.freeze(id, userId, days: days);
|
||||
return ApiResponse.success(result, message: result['message'] as String);
|
||||
}
|
||||
|
||||
Future<Response> _getHistory(Request request, String id) async {
|
||||
final userId = request.context['userId'] as String;
|
||||
final history = await _service.getHistory(id, userId);
|
||||
return ApiResponse.success(history);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user