CAMDOM — Code Quality, Patterns & Technical Debt
Code review: quality metrics, naming conventions, structural patterns, error handling, code duplication, type safety, technical debt, commit analysis.
CAMDOM — Code Quality, Patterns & Technical Debt
Project Overview
| Metric | Value |
|---|---|
| Total Commits | 429 |
| Date Range | 2024-06-06 to 2025-11-16 (17 months) |
| Contributors | 6 (alefita: 142, GitHub Action: 116, alefita-p4b: 90, Mikael: 46, Alef Oliveira: 22, Victor: 8) |
| Total Source Lines | ~8,967 (TypeScript + Kotlin + Swift) |
| TypeScript Strict Mode | Enabled |
| Test Coverage | 0% — No test files exist |
1. Code Quality Metrics
File Sizes (Largest to Smallest)
| Rank | File | Lines | Category |
|---|---|---|---|
| 1 | modules/ble-manager/src/BleManager.ts | 1,877 | BLE Logic (God Object) |
| 2 | app/index.tsx | 918 | Main UI Screen |
| 3 | modules/ble-manager/android/.../BleManager.kt | 753 | Android Native BLE |
| 4 | modules/ble-manager/android/.../BlePeripheralManager.kt | 452 | Android Peripheral |
| 5 | modules/ble-manager/ios/BlePeripheralManager.swift | 273 | iOS Peripheral |
| 6 | utils/i18n.ts | 247 | Internationalization |
| 7 | app/onboarding.tsx | 246 | Onboarding UI |
| 8 | components/Menu/MenuList.tsx | 237 | Menu Component |
| 9 | utils/Animations.ts | 164 | Animation Engine |
| 10 | components/Menu/MenuTitle.tsx | 159 | Menu Title |
Critical Finding: BleManager.ts at 1,877 lines is 25.9% of all TypeScript source code. This is a textbook god object antipattern.
TypeScript any Usage
| Type | Count | Location |
|---|---|---|
Explicit any type annotations | 5 | BleManager.ts:873,886,892 (event handler) |
as any type casts | 3 | BleManager.ts (event casting) |
Total any violations | 8 | All in BleManager.ts |
Lines with any:
- Line 873:
emit(name: EventNames, ...args: any[]) - Line 885:
(event as any).value.data - Line 892:
(event as any).value
TODO/FIXME/HACK Markers
| File | Line | Marker | Content |
|---|---|---|---|
BleManager.kt | 319 | TODO | timeout timer: if callback not called - disconnect, wait 120ms, close |
BleManager.kt | 329 | TODO | bonding state |
BleManager.kt | 344 | TODO | random error 133 - close and try reconnect |
BleManager.kt | 391 | WARN | characteristic not found $CHAR_FOR_INDICATE_UUID |
Analysis: All TODOs are in the Android native layer, indicating incomplete BLE error recovery. The error 133 handler (line 344) is a known Android BLE issue that remains unimplemented.
Commented-Out Code Blocks
| File | Lines | Count | Feature |
|---|---|---|---|
BleManager.ts | 587-589 | 3 | Debug logging for device scan |
BleManager.ts | 1106-1113 | 8 | RSSI proximity sensor activation |
BleManager.ts | 1198-1205 | 8 | RSSI proximity sensor activation (duplicate) |
BleManager.ts | 1268-1275 | 8 | RSSI proximity sensor activation (duplicate) |
BleManager.ts | 1463-1468 | 6 | Proximity notification UI |
BleManager.ts | 1483-1491 | 9 | RSSI notification handler |
BleManager.ts | 1799-1804 | 6 | Client RSSI packet sending |
BleManager.ts | 1814-1849 | 36 | Server RSSI processing + alarm firing |
BleManager.ts | 1868-1870 | 3 | RSSI timeout configuration |
Options.tsx | 117-144 | 28 | Sign out + Delete account buttons |
| Total | ~115 |
Critical Finding: 109 lines of commented-out code in BleManager.ts alone. The RSSI proximity feature is completely disabled but remains as zombie code. The Options.tsx file has commented-out authentication features (sign out, delete account).
Magic Numbers vs Named Constants
| Magic Number | Location | Context | Should Be |
|---|---|---|---|
125, 124, 126, 249, 251 | BleManager.ts:499-507 | Advertising value ranges | Named constants for iOS/Android ranges |
53 | BleManager.ts:909 | MTU request size | const MTU_SIZE = 53 |
8 | BleManager.ts:438 | Session ID substring length | const SESSION_ID_LENGTH = 8 |
7500 | BleManager.ts:768 | Scanning timeout ms | const SCAN_TIMEOUT_MS = 7500 |
500 | BleManager.ts:1001 | Server disconnection poll interval | const DISCONNECT_POLL_MS = 500 |
3500 | BleManager.ts:1114 | RSSI reader delay | const RSSI_DELAY_MS = 3500 |
300 | BleManager.ts:981 | Connection sleep delay | const CONNECTION_DELAY_MS = 300 |
15 | BleManager.ts:1803,1848 | RSSI tick rate | const RSSI_TICK_MS = 15 |
5 | BleManager.ts:1859 | RSSI history buffer size | const RSSI_BUFFER_SIZE = 5 |
10 | BleManager.ts:601 | iOS scan retry limit | const IOS_SCAN_RETRY_LIMIT = 10 |
1800 | BleManager.ts:1514 | Ping pong timeout | const PING_PONG_TIMEOUT_MS = 1800 |
600 | BleManager.ts:1523 | Disconnect acknowledgment delay | const DISCONNECT_ACK_MS = 600 |
1500 | BleManager.ts:1296 | Client disconnect timeout | const CLIENT_DISCONNECT_TIMEOUT_MS = 1500 |
Result: 13+ magic numbers identified. Zero named constants for timing/range values.
2. Naming Conventions Analysis
TypeScript Conventions
| Pattern | Status | Examples |
|---|---|---|
| camelCase functions | PASS | startScanning(), stopAdvertising(), handlePacketFromServer() |
| PascalCase components | PASS | LateralMenu, Options, MenuList, MenuTitle |
| PascalCase interfaces | PASS | UISharedValues, EventBase, EventWithPayload |
| SCREAMING_SNAKE constants | PARTIAL | SERVICE_UUID, CHAR_FOR_READ_UUID (BLE UUIDs only) |
Boolean naming with is/has | PASS | isScanning, isConnecting, isServer, hasConnectionError |
Issues Found:
AvailablePositionstype at line 53:"center" | "center" | "center"— duplicate union members (likely a bug or dead code)randomIntFromInterval(line 491) — should begetRandomIntorrandomIntPacketToSoundsMapperandSoundsToPacketMapper— inconsistent naming (one usesTo, other usesToPacket)
Cross-Language Consistency (TS → Kotlin → Swift)
| Concept | TypeScript | Kotlin | Swift |
|---|---|---|---|
| BLE Manager | BleManager | BleManager | BlePeripheralManager |
| Service UUID | SERVICE_UUID | SERVICE_UUID | SERVICE_UUID |
| Characteristic UUID | CHAR_FOR_READ_UUID | CHAR_FOR_READ_UUID | CHAR_FOR_INDICATE_UUID |
| Broadcast packet | broadcastPacket() | broadcastPacket() | broadcastPacket() |
| Send to client | sendPacketToClient() | sendPacketToClient() | — |
Finding: Naming is largely consistent across languages. The iOS implementation uses BlePeripheralManager instead of BleManager, which is a minor inconsistency but semantically accurate (iOS focuses on peripheral role).
3. Structural Patterns
The "God Object" Problem — BleManager.ts
BleManager.ts at 1,877 lines contains:
| Responsibility | Lines | Methods |
|---|---|---|
| BLE state management | ~200 | 15+ private state variables |
| Sound effects | ~80 | bindSoundEffects(), playSound() |
| Event listeners | ~230 | bindListeners() |
| Scanning logic | ~180 | startScanning(), stopScanning(), configureScanTimeout() |
| Connection management | ~150 | registerClientCallbacks(), disconnectFromServer() |
| Packet handling (server) | ~220 | handlePacketFromClient() |
| Packet handling (client) | ~200 | handlePacketFromServer() |
| UI interactions | ~180 | onDisconnectPressStart(), onDisconnectPressFinish(), onStopAlarmPressStart() |
| RSSI proximity (disabled) | ~80 | configureClientRSSITimeout(), configureServerRSSITimeout() |
| Storage initialization | ~10 | Constructor |
Recommendation: Split into:
BleConnectionManager— scanning, connecting, disconnectingBlePacketHandler— packet parsing and routingBleSoundManager— audio effectsBleRssiMonitor— proximity detection (currently disabled)BleStateManager— SharedValue management
Module Separation
modules/
├── ble-manager/ # BLE native module (Expo Module)
│ ├── src/ # TypeScript layer
│ │ ├── BleManager.ts # 1,877 lines — GOD OBJECT
│ │ ├── Events.types.ts
│ │ ├── Utils.ts
│ │ └── BleManagerModule.ts
│ ├── android/ # Kotlin implementation
│ │ └── src/main/java/p4b/modules/blemanager/
│ │ ├── BleManager.kt (753 lines)
│ │ ├── BlePeripheralManager.kt (452 lines)
│ │ └── BleManagerModule.kt (56 lines)
│ └── ios/ # Swift implementation
│ ├── BlePeripheralManager.swift (273 lines)
│ └── BleManagerModule.swift (42 lines)
├── app/ # UI screens
│ ├── index.tsx (918 lines)
│ └── onboarding.tsx (246 lines)
├── components/ # Reusable UI
│ ├── LateralMenu/ # 6 files
│ └── Menu/ # 7 files
├── hooks/ # Custom React hooks
│ └── useLateralMenu.tsx
└── utils/ # Utilities
├── Animations.ts # Generator-based animation engine
├── i18n.ts
└── requestPermissions.ts
Issues:
- No clear separation between UI and business logic
app/index.tsxat 918 lines is also oversized- No service layer or repository pattern
- BLE protocol logic mixed with UI state management
File Naming Conventions
| Pattern | Status | Examples |
|---|---|---|
| PascalCase components | PASS | LateralMenu.tsx, Options.tsx, MenuList.tsx |
| camelCase hooks | PASS | useLateralMenu.tsx |
| camelCase utilities | PASS | Animations.ts, i18n.ts, requestPermissions.ts |
| PascalCase classes | PASS | BleManager.ts |
| Consistent extensions | PASS | .tsx for components, .ts for logic |
4. Error Handling Audit
Try/Catch Blocks in BleManager.ts
| Line | Context | Handling Quality |
|---|---|---|
| 194-206 | Audio.setAudioModeAsync() | POOR — Sets isAudioModeSet = false but no user feedback |
| 511-521 | startAdvertising() | POOR — Silently retries permissions, no error propagation |
| 649-673 | device.connect() | GOOD — Logs error, updates UI state, sets hasConnectionError |
| 794-797 | connectedDevice.cancelConnection() | POOR — Empty catch: //ignore |
| 824-865 | sendPacketToServer() | GOOD — Logs error, disconnects, updates UI |
| 928-955 | monitorCharacteristicForService() | POOR — Updates UI but no error logging |
Total catch blocks: 6
Empty/ignoring catch blocks: 1 (cancelConnection)
Silent failures: 2 (setAudioModeAsync, startAdvertising)
Missing Error Handling
| Location | Risk |
|---|---|
bindSoundEffects() (line 177) | No catch — if audio files fail to load, isSoundsLoaded stays false |
registerClientCallbacks() (line 902) | No catch on discoverAllServicesAndCharacteristics() |
handlePacketFromServer() (line 1327) | No validation of packet format before parsing |
handlePacketFromClient() (line 1529) | No validation of packet.data format |
playSound() (line 217) | No catch on setVolume() or replayAsync() |
Error Propagation Pattern
Native Module Error
↓
TypeScript Event Emitter
↓
BleManager Event Handler
↓
SharedValue UI State Update
↓
React Component Re-render
↓
Snackbar.show() (optional)
Issues:
- Errors are swallowed in 33% of catch blocks
- No centralized error handling or error boundary
- User-facing errors only shown via Snackbar (no retry mechanism)
- No error codes or structured error objects
5. Code Duplication
Lateral Menu Components (6 files)
| File | Lines | Animation Pattern |
|---|---|---|
LateralMenu.tsx | 73 | makeAnimation + stagger + timing |
MenuIcon.tsx | 79 | makeAnimation + stagger + timing |
CamdomLogo.tsx | — | Same pattern |
UnlockYourPleasure.tsx | — | Same pattern |
BuyAComdomLateralText.tsx | 79 | Same pattern |
BillyBoyVerticalLogo.tsx | — | Same pattern |
Duplication: Each component independently defines:
const animation = makeAnimation(
function* ({ isOpened, display, transition }) {
"worklet";
let to = 1;
while (true) {
yield* waitUntil(isOpened, !to);
display.value = isOpened.value;
yield* stagger(duration / 2, timing(transition, { to, duration }));
to = to === 1 ? 0 : 1;
}
},
{ isOpened: false, display: false, transition: 0 }
);
Recommendation: Extract to useMenuAnimation() hook with configurable duration and stagger delay.
State Reset Code in BleManager.ts
The following block appears 5 times with minor variations (lines 317-333, 366-372, 529-534, 690-698, 1033-1044):
this.allowedClientsToDisconnect = [];
this.askedDisconnectionDevices = [];
this.askedToStopAlarmClients = [];
this.rssiUpdatesFromClients = new Map<string, number[]>();
this.connectedDevice = undefined; // or this.connectedClients = []
this.lastDisconnectedDevice = undefined;
this.hasAnyoneRequestedToFireWhenDisconnect = false;
this.hasAnyoneHigherSensibility = undefined;
Recommendation: Extract to resetConnectionState() method.
Disconnection Handler Duplication
onDisconnectPressFinish() (lines 1058-1146) and onDisconnectLongPress() (lines 1148-1225) share ~80% identical code for server-side disconnection handling. The only difference is the long press version sets hasConnectionError = false.
6. Type Safety
TypeScript Strict Mode Status
Enabled in tsconfig.json:
{
"compilerOptions": {
"strict": true
}
}
Interface vs Type Usage
| Pattern | Count | Location |
|---|---|---|
interface declarations | 4 | Events.types.ts:1,3,7,14 |
type declarations | 5 | BleManager.ts:44,53,102 |
| Mixed usage | YES | Inconsistent |
Issues:
UISharedValuesusesinterface(line 92)AppConnectionStateusestype(line 44)- No clear rule for when to use
interfacevstype
SharedValue Type Safety
| SharedValue | Type | Line | Safety |
|---|---|---|---|
isPeripheralServer | SharedValue<boolean> | 93 | SAFE |
hasConnectionError | SharedValue<boolean> | 94 | SAFE |
alarmButtonPosition | SharedValue<AvailablePositions> | 95 | SAFE |
ballPosition | SharedValue<AvailablePositions> | 96 | SAFE |
ballRadius | SharedValue<number> | 97 | SAFE |
ballText | SharedValue<string[]> | 98 | SAFE |
appState | SharedValue<AppConnectionState> | 99 | SAFE |
Finding: SharedValue types are well-defined. However, AvailablePositions type (line 53) is suspicious:
export type AvailablePositions = "center" | "center" | "center";
This appears to be a bug — likely should be "left" | "center" | "right".
Critical Type Bug
AvailablePositions at line 53:
export type AvailablePositions = "center" | "center" | "center";
This type only allows "center" as a value. If the ball/alarm positions are supposed to move left/right, this type is broken. The animation code references "left" and "right" positions, but the type system would reject them.
7. Technical Debt Inventory
Deprecated APIs
| API | Location | Replacement |
|---|---|---|
expo-modules-core EventEmitter | BleManager.ts:3 | Modern Expo Module API |
react-native-ble-plx BlePlxManager | BleManager.ts:21-26 | Consider Expo BLE native module |
btoa() / atob() | BleManager.ts:831,937 | Use TextEncoder/TextDecoder |
Workarounds & Hacks
| Issue | Location | Description |
|---|---|---|
| Platform-specific scan delay | BleManager.ts:716 | Platform.OS === "ios" ? 400 : 0 — iOS needs 400ms delay before scanning |
| MTU negotiation | BleManager.ts:909 | Hardcoded requestMTU(53) — should negotiate |
| Session ID truncation | BleManager.ts:438 | uuid.v4().substring(0, 8) — arbitrary truncation |
| iOS scan retry logic | BleManager.ts:601-608 | Complex retry with scanCountRetriesIos counter |
| Volume manager workaround | BleManager.ts:235-238 | Forces volume to 1 before playing sounds |
Commented-Out Features
| Feature | Lines | Status |
|---|---|---|
| RSSI Proximity Detection | 1791-1871 | DISABLED — 80 lines of dead code |
| Proximity Notifications | 1106-1113, 1198-1205, 1268-1275 | DISABLED — Snackbar UI for proximity |
| RSSI Packet Sending | 1799-1804 | DISABLED — Client RSSI reporting |
| Sign Out / Delete Account | Options.tsx:117-144 | DISABLED — Authentication features |
Zombie Variables (Allocated but Unused)
| Variable | Line | Purpose |
|---|---|---|
isAmIClientAllowedToDisconnectEdgeCase | 116 | Complex disconnection state |
hasAnyoneHigherSensibility | 142 | RSSI sensitivity (disabled feature) |
distanceAlarmFired | 149 | Distance-based alarm (disabled feature) |
timeoutRssiReader | 150 | RSSI reader timeout (disabled feature) |
pingPongTimeout | 151 | Ping pong protocol timeout |
Missing Tests
Zero test files found. No .test.ts, .test.tsx, .spec.ts, or .spec.tsx files exist in the entire codebase.
Risk Areas Without Tests:
- BLE packet parsing (custom protocol)
- State machine transitions
- Connection/disconnection logic
- RSSI threshold calculations (disabled but still in code)
- Sound effect loading and playback
8. Commit Quality Analysis
Message Quality
| Category | Count | Percentage |
|---|---|---|
| Semantic (feat/fix/chore) | ~120 | 28% |
| Descriptive | ~280 | 65% |
| WIP/Temporary | ~29 | 7% |
WIP Commits Found
| Hash | Message |
|---|---|
8db976f | wip |
b19cdc4 | final bitch - wip |
8712884 | wip: almost alive babe |
Time-of-Day Patterns
Based on commit timestamps, development peaks at:
- Evening (17:00-19:00 BRT) — Most commits
- Night (21:00-02:00 BRT) — Significant activity
- Early Morning (03:00-06:00 BRT) — Some commits present
Fix-Heavy Periods
| Period | Pattern |
|---|---|
| Initial setup (Jun 2024) | Build configuration fixes |
| Nov 2025 | Final push with rapid fixes |
9. Architectural Strengths
Generator-Based Animation Engine (utils/Animations.ts)
Lines: 164
This is an elegant, production-quality animation system:
export function* timing(value: SharedValue<number>, rawConfig?: TimingConfig) {
"worklet";
const from = value.value;
const { to, easing, duration } = { ...defaultTimingConfig, ...rawConfig };
const start: number = yield;
const end = start + duration;
for (let current = start; current < end; ) {
const progress = easing((current - start) / duration);
const val = interpolate(progress, [0, 1], [from, to]);
value.value = val;
current += yield* timeSincePreviousFrame();
}
value.value = to;
}
Strengths:
- Leverages JavaScript generators for imperative-style async animations
- Composable via
parallel()andstagger() - Runs on UI thread via
"worklet"directive - Clean API:
yield* timing(value, { to: 1, duration: 300 })
Custom BLE Protocol
The packet protocol is purpose-built and efficient:
c:0:125 → Connection (role:client, advertisingValue:125)
s:a|session1 → Session answer (sessionId: session1)
d:r|s → Disconnection request start
a:f|1|u → Alarm fire (action:1, source:user)
sound:1|3 → Sound play (type:1, sound:alarm)
n:rssi|1|45|null → RSSI update (enabled:1, value:45, sense:null)
Strengths:
- Minimal overhead (ASCII-encoded, ~20 bytes typical)
- Bidirectional (server/client roles)
- Self-describing (colon-delimited type:content)
- Supports migration (device role switching)
Skia Rendering
- GPU-accelerated rendering via
@shopify/react-native-skia - No bridge overhead for animations
- Custom font rendering with
ParagraphAPI - Shader-based effects (blur, image shaders)
Privacy by Design
- No network calls except BLE (peer-to-peer)
- No analytics or telemetry
- No data collection — all state is local (MMKV)
- No server dependency — fully decentralized
10. Architectural Weaknesses
BleManager as Monolith
1,877 lines handling:
- BLE scanning
- Connection management
- Packet parsing/routing
- Sound effects
- UI state synchronization
- RSSI monitoring (disabled)
- Storage initialization
Impact:
- Changes to one feature risk breaking others
- Difficult to test in isolation
- Merge conflicts likely in team development
- Cognitive load for new developers
Shared State Sprawl
11 SharedValues managed by BleManager:
interface UISharedValues {
isPeripheralServer: SharedValue<boolean>;
hasConnectionError: SharedValue<boolean>;
alarmButtonPosition: SharedValue<AvailablePositions>;
ballPosition: SharedValue<AvailablePositions>;
ballRadius: SharedValue<number>;
ballText: SharedValue<string[]>;
appState: SharedValue<AppConnectionState>;
}
Plus 15 private state variables:
private isServer?: boolean;
private isScanning = false;
private isConnecting = false;
private connectedDevice?: Device;
private connectedClients: string[] = [];
// ... 10 more
Total state count: 22 state variables in a single class.
Missing Abstractions
| Pattern | Status | Impact |
|---|---|---|
| Repository Pattern | MISSING | Direct MMKV access scattered across codebase |
| Service Layer | MISSING | Business logic mixed with UI |
| State Machine | MISSING | Connection states managed via if/else chains |
| Dependency Injection | MISSING | Singleton pattern (const manager = new BleManager(...)) |
| Event Bus | PARTIAL | Native EventEmitter used, but not centralized |
No Tests
Risk Assessment:
| Component | Risk | Reason |
|---|---|---|
| BLE Protocol | CRITICAL | Custom packet format, no validation |
| State Transitions | HIGH | Complex conditional logic |
| Connection Logic | HIGH | Race conditions possible |
| Sound Effects | MEDIUM | Platform-specific behavior |
| UI Animations | LOW | Visual feedback only |
No CI/CD Quality Gates
No evidence of:
- Linting (ESLint)
- Type checking (
tsc --noEmit) - Test execution
- Code coverage
- Bundle size analysis
- Automated code review
11. Cross-Language Naming Inconsistencies
| Concept | TypeScript | Kotlin | Swift | Issue |
|---|---|---|---|---|
| Main class | BleManager | BleManager | BlePeripheralManager | iOS naming differs |
| Read characteristic | CHAR_FOR_READ_UUID | CHAR_FOR_READ_UUID | — | iOS doesn't use read char |
| Indicate characteristic | CHAR_FOR_INDICATE_UUID | CHAR_FOR_INDICATE_UUID | CHAR_FOR_INDICATE_UUID | Consistent |
| Broadcast method | broadcastPacket() | broadcastPacket() | broadcastPacket() | Consistent |
| Send to client | sendPacketToClient() | sendPacketToClient() | — | iOS handles differently |
Finding: Naming is largely consistent. The iOS BlePeripheralManager name is semantically accurate (iOS BLE peripherals have different APIs than Android).
12. Protocol-Level Issues
Packet Validation
No validation on incoming packets:
// BleManager.ts:1327
private async handlePacketFromServer(packet: string) {
const packetType = packet.split(":")[0]; // Could crash if no ":"
const packetContent = packet.split(":")[1]; // Could be undefined
// ...
}
Risks:
- Malformed packets could crash the app
- No bounds checking on array access
- No packet authentication
Race Conditions
Multiple async operations without proper locking:
// BleManager.ts:539-544
async startScanning() {
this.isScanning = true; // Set immediately
// ... async operations ...
// isScanning could be false before async completes
}
Memory Leaks
Potential leaks in event listeners:
// BleManager.ts:253
const subscriptions = [];
subscriptions.push(
AppState.addEventListener("change", (state) => {
// Closure captures `this`
})
);
If bindListeners() is called multiple times, old subscriptions aren't cleaned up.
13. Recommendations
Immediate (Quick Wins)
- Extract magic numbers to named constants
- Fix
AvailablePositionstype — should be"left" | "center" | "right" - Remove commented-out code — 115 lines of dead code
- Add error logging to silent catch blocks
- Fix
cancelConnectionempty catch — at minimum log the error
Short-Term (1-2 weeks)
- Split
BleManager.tsinto 4-5 focused modules - Extract
resetConnectionState()method - Add packet validation in
handlePacketFromServerandhandlePacketFromClient - Add ESLint with strict rules
- Add TypeScript CI check (
tsc --noEmit)
Medium-Term (1 month)
- Implement state machine for connection states
- Add unit tests for BLE protocol parsing
- Extract animation hooks from lateral menu components
- Remove disabled RSSI feature or implement properly
- Add integration tests for BLE connection flow
Long-Term (3 months)
- Add repository pattern for storage access
- Implement dependency injection for testability
- Add E2E tests with Detox
- Set up CI/CD with quality gates
- Consider architecture overhaul — MVVM or Clean Architecture
14. Summary Scorecard
| Category | Score | Grade |
|---|---|---|
| Code Organization | 4/10 | D |
| Type Safety | 6/10 | C |
| Error Handling | 4/10 | D |
| Test Coverage | 0/10 | F |
| Documentation | 2/10 | F |
| Naming Conventions | 7/10 | B- |
| Code Duplication | 3/10 | D |
| Technical Debt | 3/10 | D |
| Architecture | 4/10 | D |
| Overall | 3.6/10 | D- |
Key Strengths
- Generator-based animation engine (elegant, composable)
- Custom BLE protocol (efficient, purpose-built)
- Privacy by design (no data collection)
- TypeScript strict mode enabled
Key Weaknesses
- God object antipattern (BleManager: 1,877 lines)
- Zero test coverage
- 115 lines of commented-out code
- 13+ magic numbers
- 22 state variables in single class
- No CI/CD quality gates
Appendix: File Line Counts
7281 total
1877 ./modules/ble-manager/src/BleManager.ts
918 ./app/index.tsx
753 ./modules/ble-manager/android/.../BleManager.kt
452 ./modules/ble-manager/android/.../BlePeripheralManager.kt
273 ./modules/ble-manager/ios/BlePeripheralManager.swift
247 ./utils/i18n.ts
246 ./app/onboarding.tsx
237 ./components/Menu/MenuList.tsx
164 ./utils/Animations.ts
159 ./components/Menu/MenuTitle.tsx
147 ./components/Menu/MenuContent/Pages/Options/Options.tsx
128 ./components/NoisyBlurredBackground.tsx
101 ./components/Menu/MenuContent/MenuContent.tsx
99 ./hooks/useLateralMenu.tsx
81 ./components/Menu/Menu.tsx
79 ./components/LateralMenu/MenuIcon.tsx
79 ./components/LateralMenu/BuyAComdomLateralText.tsx
77 ./components/LateralMenu/styles.ts
73 ./components/LateralMenu/LateralMenu.tsx
This analysis reflects the codebase as of November 2025 (429 commits). The codebase demonstrates strong domain expertise in BLE protocol design and animation systems, but suffers from typical startup engineering tradeoffs: rapid iteration at the expense of maintainability. The generator-based animation engine is production-quality; the BLE manager needs architectural refactoring.