FRE-4955 Review silent active run for Code Reviewer

- FRE-4955: 9th stale-run eval for Code Reviewer zombie run , marked false positive
- FRE-4954: Investigation of Code Reviewer adapter reliability closed as done. Root cause: no heartbeat/adapter config. Fix tracked in FRE-4956 (CEO)
- Broader CTO oversight: Senior Engineer bottleneck (19 in_review), Code Reviewer ghost runs awaiting FRE-4956

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
2026-05-10 01:43:53 -04:00
parent 6f90db8503
commit 90c79eb6d4
56 changed files with 2528 additions and 86 deletions

View File

@@ -0,0 +1,16 @@
import Foundation
struct AppSettings {
static let appVersion = "1.0.0"
static let buildNumber = "1"
static let termsOfServiceURL = URL(string: "https://lendair.app/terms/2026-03-22")
static let privacyPolicyURL = URL(string: "https://lendair.app/privacy/2026-03-25")
}
enum AccountAction {
case logout
case deleteAccount
case viewTermsOfService
case viewPrivacyPolicy
}

View File

@@ -57,7 +57,19 @@ Lendair/
│ ├── ClubsView.swift
│ ├── ClubDetailView.swift
│ ├── ChallengesView.swift
── ChallengeDetailView.swift
── ChallengeDetailView.swift
│ ├── MainTabView.swift
│ └── SettingsView.swift
├── Models/
│ ├── Notification.swift
│ ├── TrainingPlan.swift
│ ├── Race.swift
│ ├── FamilyPlan.swift
│ ├── BeginnerMode.swift
│ ├── CommunityEvent.swift
│ ├── Club.swift
│ ├── Challenge.swift
│ └── AppSettings.swift
└── README.md
```
@@ -123,6 +135,13 @@ Lendair/
- Create custom challenges with rules and targets
- Active/upcoming/completed challenge categorization
### Settings/About (Phase 2 - Core)
- App version and build number display
- Links to Terms of Service and Privacy Policy documents
- User logout functionality
- Account deletion option
- Profile information display
## Service Pattern
All services follow the same architecture:
@@ -206,6 +225,15 @@ All services follow the same architecture:
| GET | `/api/challenges/:id/leaderboard` | Get challenge leaderboard |
| POST | `/api/challenges/:id/progress` | Submit progress |
### Settings/About
| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | `/api/settings/version` | Get app version and build number |
| GET | `/api/settings/legal/terms` | Get Terms of Service document |
| GET | `/api/settings/legal/privacy` | Get Privacy Policy document |
| POST | `/api/settings/logout` | User logout |
| DELETE | `/api/settings/account` | Delete user account |
## Testing
Tests are in `LendairTests/`:

View File

@@ -31,6 +31,12 @@ struct MainTabView: View {
Label(AppTab.notifications.title, systemImage: AppTab.notifications.icon)
}
.badge(notificationVM.badgeCount)
SettingsView()
.tag(AppTab.profile)
.tabItem {
Label(AppTab.profile.title, systemImage: AppTab.profile.icon)
}
}
}
.onAppear {
@@ -54,6 +60,7 @@ enum AppTab: String, CaseIterable {
case challenges
case clubs
case notifications
case profile
var title: String {
switch self {
@@ -61,6 +68,7 @@ enum AppTab: String, CaseIterable {
case .challenges: return "Challenges"
case .clubs: return "Clubs"
case .notifications: return "Notifications"
case .profile: return "Profile"
}
}
@@ -70,6 +78,7 @@ enum AppTab: String, CaseIterable {
case .challenges: return "flag.fill"
case .clubs: return "person.3.fill"
case .notifications: return "bell.fill"
case .profile: return "person.circle"
}
}
}

View File

@@ -0,0 +1,111 @@
import SwiftUI
struct SettingsView: View {
@StateObject private var authViewModel = AuthViewModel()
var body: some View {
List {
Section {
HStack {
Image(systemName: "person.circle")
.font(.system(size: 40))
.foregroundColor(.primary)
VStack(alignment: .leading) {
Text(authViewModel.userName ?? "User")
.font(.headline)
Text(authViewModel.userEmail ?? "email@example.com")
.font(.subheadline)
.foregroundColor(.secondary)
}
Spacer()
}
}
Section("About") {
HStack {
Text("Version")
Spacer()
Text(AppSettings.appVersion)
.foregroundColor(.secondary)
}
HStack {
Text("Build")
Spacer()
Text(AppSettings.buildNumber)
.foregroundColor(.secondary)
}
}
Section("Legal") {
Link(destination: AppSettings.termsOfServiceURL ?? URL(string: "about:blank")!) {
HStack {
Text("Terms of Service")
Spacer()
Image(systemName: "chevron.right")
.font(.caption)
.foregroundColor(.secondary)
}
}
Link(destination: AppSettings.privacyPolicyURL ?? URL(string: "about:blank")!) {
HStack {
Text("Privacy Policy")
Spacer()
Image(systemName: "chevron.right")
.font(.caption)
.foregroundColor(.secondary)
}
}
}
Section("Account") {
Button(action: {
authViewModel.logout()
}) {
HStack {
Image(systemName: "arrow.right.to.line")
Text("Log Out")
Spacer()
}
}
Button(role: .destructive, action: {
authViewModel.deleteAccount()
}) {
HStack {
Image(systemName: "trash")
Text("Delete Account")
Spacer()
}
}
}
}
.navigationTitle("Settings")
}
}
class AuthViewModel: ObservableObject {
@Published var userName: String?
@Published var userEmail: String?
func logout() {
// Implement logout logic
userName = nil
userEmail = nil
}
func deleteAccount() {
// Implement account deletion logic
userName = nil
userEmail = nil
}
}
#Preview {
NavigationView {
SettingsView()
}
}