# ShiftRing 알람 시스템 기술 문서

## 버전 정보
- **Version**: 1.0.0
- **Build**: 100
- **지원 Android**: 8.0 (Oreo) ~ 16

---

## 1. 알람 아키텍처 개요

### 1.1 전체 흐름
```
[알람 예약] → [AlarmManager] → [AlarmReceiver] → [AlarmActivity]
     ↑              ↓                    ↓                ↓
[SharedPrefs]  [Doze Mode]      [WakeLock]      [화면 켜짐]
```

### 1.2 핵심 컴포넌트
1. **AlarmUtils.kt** - 알람 예약/취소 로직
2. **AlarmReceiver.kt** - 알람 수신 및 처리
3. **AlarmActivity.kt** - 알람 UI 및 해제
4. **AlarmForegroundService.kt** - 포그라운드 서비스

---

## 2. 알람 예약 메커니즘

### 2.1 ID 생성 체계
```kotlin
// 기본 근무 알람: 1YYMMDD0
// 예: 2026년 2월 13일 → 126021300
fun getShiftAlarmId(date: LocalDate): Int {
    return 100000000 + (date.year % 100) * 1000000 + 
           date.monthValue * 10000 + date.dayOfMonth * 100 + 0
}

// 사용자 알람: 2YYMMDDNN (NN = 인덱스)
// 예: 2026년 2월 13일, 인덱스 1 → 226021301
fun getCustomAlarmId(date: LocalDate, index: Int): Int {
    return 200000000 + (date.year % 100) * 1000000 + 
           date.monthValue * 10000 + date.dayOfMonth * 100 + index
}
```

### 2.2 Android 버전별 알람 설정

#### Android 8.0~8.1 (API 26-27)
```kotlin
// Oreo: Background 제한 대응
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, triggerTime, pendingIntent)
```

#### Android 9.0~13 (API 28-33)
```kotlin
// Pie ~ Tiramisu: setAlarmClock 권장
val clockInfo = AlarmManager.AlarmClockInfo(triggerTime, viewPendingIntent)
alarmManager.setAlarmClock(clockInfo, pendingIntent)
```

#### Android 14+ (API 34+)
```kotlin
// Upside Down Cake+: 권한 필수 + setAlarmClock
// 1. canScheduleExactAlarms() 권한 체크
// 2. setAlarmClock()으로 등록
// 3. USE_FULL_SCREEN_INTENT 권한 필요
```

### 2.3 Doze 모드 대응
```kotlin
// Doze 모드에서도 알람 실행 보장
setExactAndAllowWhileIdle()  // API 23+
setAlarmClock()              // API 21+ (권장)
```

---

## 3. 알람 수신 및 실행

### 3.1 AlarmReceiver 동작
```kotlin
override fun onReceive(context: Context, intent: Intent?) {
    // 1. WakeLock 획득 (10분)
    val wakeLock = pm.newWakeLock(
        FULL_WAKE_LOCK or ACQUIRE_CAUSES_WAKEUP or ON_AFTER_RELEASE,
        "ShiftRing::DeepWakeLock"
    )
    wakeLock.acquire(10 * 60 * 1000L)
    
    // 2. Foreground Service 시작 (Oreo+ 필수)
    context.startForegroundService(serviceIntent)
    
    // 3. Notification 발행 (전체화면 인텐트 포함)
    notificationManager.notify(1001, notification)
    
    // 4. AlarmActivity 시작
    context.startActivity(fullScreenIntent)
}
```

### 3.2 화면 켜짐 로직 (버전별)

#### Android 8.0 (Oreo)
```kotlin
// Deprecated 플래그 사용
window.addFlags(
    FLAG_SHOW_WHEN_LOCKED or
    FLAG_DISMISS_KEYGUARD or
    FLAG_TURN_SCREEN_ON
)
```

#### Android 8.1+ (Oreo MR1)
```kotlin
// 새로운 API 사용
setShowWhenLocked(true)
setTurnScreenOn(true)
keyguardManager.requestDismissKeyguard(this, null)
```

#### Android 14+ (Upside Down Cake)
```kotlin
// Keyguard dismiss 없이 위에 표시
setShowWhenLocked(true)
setTurnScreenOn(true)
window.addFlags(
    FLAG_LAYOUT_IN_SCREEN or
    FLAG_LAYOUT_INSET_DECOR
)
// Keyguard 해제 없이 바로 알람 화면!
```

---

## 4. 권한 체계

### 4.1 필수 권한

#### Android 8.0~11
- `WAKE_LOCK` - 화면 켜짐
- `FOREGROUND_SERVICE` - 포그라운드 서비스
- `RECEIVE_BOOT_COMPLETED` - 부팅 시 알람 복구

#### Android 12+ (API 31+)
추가 권한:
- `SCHEDULE_EXACT_ALARM` - 정확한 알람 예약
- 설정에서 "알람 및 리마인더" 허용 필요

#### Android 14+ (API 34+)
추가 권한:
- `USE_FULL_SCREEN_INTENT` - 전체화면 알림
- 설정에서 "전체화면 알림" 허용 필요
- Foreground Service 타입: `specialUse`

### 4.2 권한 설정 플로우
```
[앱 실행] 
  → [Android 12+] "알람 및 리마인더" 권한 확인
    → 없으면 설정 화면으로 이동
      → 사용자 수동 허용
        → canScheduleExactAlarms() = true

[Android 14+] 
  → "전체화면 알림" 권한 확인
    → 설정 → 권한 → 전체화면 알림 → 허용

[모든 버전]
  → 배터리 최적화 "제한 없음" 설정
    → 설정 → 배터리 → 배터리 사용량 → ShiftRing → 제한 없음
```

---

## 5. 근무 계산 로직

### 5.1 전주 공장 (4팀 순환)
```kotlin
val cycle = listOf(
    "석간", "석간", "석간", "휴 무", "휴 무",
    "주간", "주간", "주간", "주간", "주간", "휴 무", "휴 무",
    "야간", "야간", "야간", "야간", "야간", "휴 무",
    "석간", "석간"
) // 20일 주기

val TEAM_OFFSETS = mapOf("A" to 0, "B" to 15, "C" to 10, "D" to 5)
```

### 5.2 논산 공장 (3팀 순환)
```kotlin
// 주간 → 야간 → 석간 (3주 주기)
// 월~금 근무, 토~일 휴 무
```

### 5.3 알람 시간 매핑
```kotlin
val shiftAlarmTimes = mapOf(
    "주간" to "06:00",
    "석간" to "14:00", 
    "야간" to "22:00",
    "야간 맞교대" to "18:00"
)
```

---

## 6. 데이터 저장 구조

### 6.1 SharedPreferences
```
ShiftAlarmPrefs:
  - selected_team: String (A/B/C/D)
  - selected_factory: String (Jeonju/Nonsan)
  - time_ju: String (주간 알람 시간)
  - time_seok: String (석간 알람 시간)
  - time_ya: String (야간 알람 시간)
  - custom_alarms: String (JSON 배열)
  - snooze_min: Int (스누즈 시간)
```

### 6.2 Room Database
```kotlin
@Entity(tableName = "shift_overrides")
data class ShiftOverride(
    val factory: String,
    val team: String,
    val date: String, // YYYY-MM-DD
    val shift: String,
    val manualAlarmTime: String? // HH:MM
)
```

---

## 7. 알람 동기화 프로세스

### 7.1 동기화 트리거
1. 앱 실행 시 (onResume)
2. 설정 변경 시 (근무/시간/팀)
3. 부팅 완료 시 (BootReceiver)
4. 날짜 변경 시 (매일 자정)

### 7.2 동기화 단계
```kotlin
suspend fun syncAllAlarms(context: Context) {
    // 1. 기존 알람 모두 취소 (7일치)
    for (date in today..today+7) {
        cancelShiftAlarm(date)
        cancelCustomAlarms(date)
    }
    
    // 2. 사용자 알람 JSON 파싱
    val customAlarms = parseCustomAlarms()
    
    // 3. 알람 재등록 (7일치)
    for (date in today..today+7) {
        val shift = calculateShift(date)
        
        // 기본 알람 등록
        if (isWorkShift(shift)) {
            scheduleShiftAlarm(date, shift, alarmTime)
        }
        
        // 사용자 알람 등록
        for (alarm in customAlarms) {
            if (shouldTrigger(alarm, shift)) {
                scheduleCustomAlarm(date, alarm)
            }
        }
    }
}
```

---

## 8. 문제 해결 가이드

### 8.1 알람이 안 울림

#### 원인 1: 권한 없음 (Android 12+)
**증상**: Log에 `canScheduleExactAlarms() = false`
**해결**: 
```
설정 → 앱 → ShiftRing → 권한 → "알람 및 리마인더" → 허용
```

#### 원인 2: 배터리 최적화
**증상**: Doze 모드에서 알람 지연/실패
**해결**:
```
설정 → 배터리 → 배터리 사용량 → ShiftRing → "제한 없음"
```

#### 원인 3: 잠금 화면 표시 안됨 (Android 14+)
**증상**: 알람은 울리지만 화면 안 켜짐
**해결**:
```
설정 → 앱 → ShiftRing → 권한 → "전체화면 알림" → 허용
```

### 8.2 로그 확인 방법
```bash
# 필수 로그
adb logcat -s AlarmReceiver:D ShiftAlarm:D *:S

# 전체 로그
adb logcat | grep -E "ShiftRing|Alarm"
```

### 8.3 정상 동작 확인 로그
```
AlarmReceiver: ===== 알람 수신 =====
AlarmReceiver: 근무: 주간 | ID: 126021300
AlarmReceiver: WakeLock 획득 완료
AlarmReceiver: Foreground Service 시작
AlarmReceiver: Notification 발행 완료
AlarmActivity: 화면 켜짐 성공
```

---

## 9. 업데이트 시스템

### 9.1 버전 확인 URL
```
https://git.webpluss.net/sanjeok77/ShiftRing/version.json
```

### 9.2 version.json 형식
```json
{
  "versionCode": 100,
  "versionName": "1.0.0",
  "apkUrl": "https://git.webpluss.net/sanjeok77/ShiftRing/releases/download/v1.0.0/app.apk",
  "changelog": "버그 수정 및 성능 개선"
}
```

### 9.3 자동 업데이트 플로우
```
[앱 실행] 
  → [서버 버전 확인]
    → [최신 버전 비교]
      → [업데이트 다이얼로그 표시]
        → [APK 다운로드]
          → [설치 진행]
```

---

## 10. 릴리즈 히스토리

### v1.0.0 (Build 100)
- 최초 릴리즈
- Android 8.0 ~ 16 지원
- Android 14+ 잠금 화면 위 알람 표시 개선
- Oreo 호환성 강화

---

## 부록: 개발자 참고사항

### A. PendingIntent Flags
- `FLAG_UPDATE_CURRENT` - 기존 인텐트 업데이트
- `FLAG_IMMUTABLE` - Android 12+ 필수 (보안)
- `FLAG_NO_CREATE` - 기존 확인용

### B. WakeLock 종류
- `FULL_WAKE_LOCK` - 화면 + 키보드 백라이트 켜짐
- `ACQUIRE_CAUSES_WAKEUP` - 획득 시 즉시 화면 켜짐
- `ON_AFTER_RELEASE` - 해제 후에도 일정 시간 유지

### C. Foreground Service Types (Android 14+)
- `specialUse` - 특수 목적 (알람 앱)
- `dataSync` - 데이터 동기화
- `location` - 위치 추적

---

**문서 버전**: 1.0.0  
**최종 수정**: 2026-02-13
