가입 약관 동의 기록 · 서비스 탈퇴 · 온보딩 6단계 · Coach Mark

This commit is contained in:
Sn-Kinos
2026-10-05 22:48:25 +09:00
parent e7010010bb
commit 55424bd4a2
36 changed files with 2884 additions and 77 deletions
+6
View File
@@ -814,12 +814,18 @@ abstract interface class MyRepository {
/// 앱 버전. 명세 — *최신버전 → 「최신 버전」 · 이전버전 → 「n.n」*.
Future<({String current, bool latest})> appVersion();
/// 서비스 탈퇴 — `fnAccountWithdraw`(Figma `554:24885`). SNS 연동이 남아 있으면 E-AUTH-14.
Future<void> withdraw();
}
/// 서버가 붙기 전까지 쓰는 표본. **정책값이 아니다.**
class SampleMyRepository implements MyRepository {
SampleMyRepository();
@override
Future<void> withdraw() async {}
static final _base = DateTime(2026, 9, 1, 12);
String _nickname = '아미보이';
@@ -112,7 +112,8 @@ class FirestoreMyRepository extends SampleMyRepository {
// **이메일 앞부분을 쓰지 않는다** — 프로필 수정이 그 값을 그대로
// 닉네임으로 저장해 홈 기여자명으로 퍼졌다. 이메일은 설정 「계정 정보」
// (명세 `554:22634` *닉네임 · 가입 이메일 값*)에만 둔다.
final email = _backend.email ?? '';
// Kakao(커스텀 토큰)는 Auth 이메일이 비어 있어 서버가 사용자 문서에 남긴 동의 이메일을 먼저 본다.
final email = user.strOr('email', _backend.email ?? '');
final photoUrl = user.strOr('photoUrl');
@@ -167,6 +168,9 @@ class FirestoreMyRepository extends SampleMyRepository {
}, SetOptions(merge: true));
}
@override
Future<void> withdraw() => _backend.call('fnAccountWithdraw');
@override
Future<void> updateNickname(String nickname) async {
final uid = _backend.requireUid;
+34 -7
View File
@@ -1,4 +1,8 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import '../../core/data/backend.dart' show BackendException;
import '../../core/i18n/app_locale.dart';
import '../../core/push/push_messaging.dart';
@@ -230,7 +234,7 @@ class _SettingsScreenState extends State<SettingsScreen> {
title: l10n.settingsWithdrawConfirm,
body: l10n.settingsWithdrawBody,
action: l10n.settingsWithdraw,
withdraw: true,
onConfirm: _withdraw,
),
),
],
@@ -339,6 +343,34 @@ class _SettingsScreenState extends State<SettingsScreen> {
await LocaleScope.maybeOf(context)?.select(picked);
}
/// 서비스 탈퇴 — 명세 `554:24885` 「연동 상태값이 있을 경우 비정상 탈퇴 처리 · 게시물 보존 ·
/// 탈퇴 처리 후 앱 종료」. 연동이 남아 있으면 비정상 탈퇴 안내(`554:24908` · `374:14699`)만 띄운다.
/// 서버도 같은 조건을 다시 본다(E-AUTH-14).
Future<void> _withdraw() async {
final l10n = context.l10n;
if (_linked.values.where((e) => e != null).length > 1) {
await _notice(l10n.settingsWithdrawLinked);
return;
}
try {
// 푸시 정리를 먼저 — 계정이 지워지면 이 기기 토큰을 지울 수 없다.
await widget.push?.clearOnSignOut();
await widget.repository.withdraw();
} on BackendException catch (e) {
if (mounted) {
await _notice(
e.code == 'E-AUTH-14' ? l10n.settingsWithdrawLinked : e.message,
);
}
return;
}
await widget.auth?.signOut();
// 「앱 종료」 — Android 만. iOS 는 앱이 스스로 종료하지 않는다(스토어 지침) — 로그인 화면으로 간다.
if (defaultTargetPlatform == TargetPlatform.android) {
await SystemNavigator.pop();
}
}
/// 안내 팝업(확인 하나) — 시안 `554:23103`.
Future<void> _notice(String message) => showAlertDialog(context, message);
@@ -347,7 +379,6 @@ class _SettingsScreenState extends State<SettingsScreen> {
required String title,
String? body,
required String action,
bool withdraw = false,
Future<void> Function()? onConfirm,
}) async {
final ok = await showConfirmDialog(
@@ -356,11 +387,7 @@ class _SettingsScreenState extends State<SettingsScreen> {
body: body,
confirmLabel: action,
);
if (ok == true && onConfirm != null) {
await onConfirm();
} else if (ok == true && withdraw && mounted) {
_toast(context.l10n.settingsWithdrawLater);
}
if (ok == true && onConfirm != null) await onConfirm();
return ok;
}
}