native-update 1.3.2 → 1.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/build.gradle +12 -0
- package/cli/package.json +1 -1
- package/docs/FIREBASE_QUERIES_AND_INDEXES_AUDIT.md +221 -0
- package/docs/PROJECT_COMPLETION_TRACKER.md +438 -239
- package/docs/REMAINING_FEATURES.md +130 -125
- package/docs/ROADMAP.md +182 -110
- package/docs/TESTING_REQUIREMENTS.md +312 -0
- package/docs/guides/BACKEND_TEMPLATES_GUIDE.md +183 -0
- package/docs/reports/COMPLETE_VERIFICATION.md +1 -1
- package/docs/reports/PRODUCTION_STATUS.md +1 -1
- package/package.json +5 -5
- package/cli/cap-update.js +0 -45
package/android/build.gradle
CHANGED
|
@@ -58,6 +58,13 @@ android {
|
|
|
58
58
|
kotlinOptions {
|
|
59
59
|
jvmTarget = '17'
|
|
60
60
|
}
|
|
61
|
+
|
|
62
|
+
testOptions {
|
|
63
|
+
unitTests {
|
|
64
|
+
includeAndroidResources = true
|
|
65
|
+
returnDefaultValues = true
|
|
66
|
+
}
|
|
67
|
+
}
|
|
61
68
|
}
|
|
62
69
|
|
|
63
70
|
repositories {
|
|
@@ -97,6 +104,11 @@ dependencies {
|
|
|
97
104
|
|
|
98
105
|
// Testing
|
|
99
106
|
testImplementation 'junit:junit:4.13.2'
|
|
107
|
+
testImplementation 'org.mockito:mockito-core:5.8.0'
|
|
108
|
+
testImplementation 'org.mockito.kotlin:mockito-kotlin:5.2.1'
|
|
109
|
+
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.3'
|
|
110
|
+
testImplementation 'com.google.truth:truth:1.1.5'
|
|
111
|
+
testImplementation 'org.robolectric:robolectric:4.11.1'
|
|
100
112
|
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
|
|
101
113
|
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
|
|
102
114
|
}
|
package/cli/package.json
CHANGED
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
# Firebase Queries and Indexes Audit
|
|
2
|
+
|
|
3
|
+
**Last Updated:** 2026-01-16
|
|
4
|
+
**Audit Status:** ✅ COMPLETE
|
|
5
|
+
**Build Status:** ✅ PASSING
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
This document tracks all Firebase Firestore queries in the project and verifies that appropriate indexes exist for each query.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Collections Used
|
|
16
|
+
|
|
17
|
+
| Collection | Purpose | Location |
|
|
18
|
+
|------------|---------|----------|
|
|
19
|
+
| `users` | User profiles and preferences | Website dashboard |
|
|
20
|
+
| `apps` | Registered applications | Website dashboard |
|
|
21
|
+
| `builds` | Build/release records | Website dashboard |
|
|
22
|
+
| `drive_tokens` | Google Drive OAuth tokens | Google Drive integration |
|
|
23
|
+
| `analytics` | Usage analytics events | Analytics tracking |
|
|
24
|
+
| `manifests` | OTA update manifests | Rollouts page |
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Firestore Rules Audit
|
|
29
|
+
|
|
30
|
+
### Root `firestore.rules` and `website/firestore.rules`
|
|
31
|
+
|
|
32
|
+
| Collection | Read | Write | Owner Check | Security Status |
|
|
33
|
+
|------------|------|-------|-------------|-----------------|
|
|
34
|
+
| `users/{userId}` | Owner only | Owner only | ✅ `userId == request.auth.uid` | ✅ Secure |
|
|
35
|
+
| `apps/{appId}` | Owner only | Owner only | ✅ `resource.data.userId == request.auth.uid` | ✅ Secure |
|
|
36
|
+
| `builds/{buildId}` | Owner only | Owner only | ✅ `resource.data.userId == request.auth.uid` | ✅ Secure |
|
|
37
|
+
| `drive_tokens/{userId}` | Owner only | Owner only | ✅ `userId == request.auth.uid` | ✅ Secure |
|
|
38
|
+
| `analytics/{eventId}` | Deny | Owner only | ✅ `request.resource.data.userId == request.auth.uid` | ✅ Secure (write-only) |
|
|
39
|
+
| Default | Deny | Deny | N/A | ✅ Secure |
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Firestore Indexes Audit
|
|
44
|
+
|
|
45
|
+
### Root `firestore.indexes.json`
|
|
46
|
+
|
|
47
|
+
| Index # | Collection | Fields | Query Purpose | Status |
|
|
48
|
+
|---------|------------|--------|---------------|--------|
|
|
49
|
+
| 1 | `apps` | `userId` ASC, `createdAt` DESC | List user's apps sorted by date | ✅ Exists |
|
|
50
|
+
| 2 | `builds` | `userId` ASC, `createdAt` DESC | List user's builds sorted by date | ✅ Exists |
|
|
51
|
+
| 3 | `builds` | `userId` ASC, `appId` ASC, `createdAt` DESC | Filter builds by app | ✅ Exists |
|
|
52
|
+
| 4 | `builds` | `userId` ASC, `channel` ASC, `createdAt` DESC | Filter builds by channel | ✅ Exists |
|
|
53
|
+
| 5 | `builds` | `userId` ASC, `status` ASC, `createdAt` DESC | Filter builds by status | ✅ Exists |
|
|
54
|
+
| 6 | `builds` | `appId` ASC, `channel` ASC, `status` ASC, `createdAt` DESC | Complex build filtering | ✅ Exists |
|
|
55
|
+
| 7 | `analytics` | `userId` ASC, `timestamp` DESC | User analytics history | ✅ Exists |
|
|
56
|
+
|
|
57
|
+
### Website `firestore.indexes.json`
|
|
58
|
+
|
|
59
|
+
Contains same indexes as root (synchronized).
|
|
60
|
+
|
|
61
|
+
### Example App Firebase Backend `example-apps/firebase-backend/firestore.indexes.json`
|
|
62
|
+
|
|
63
|
+
| Index # | Collection | Fields | Query Purpose | Status |
|
|
64
|
+
|---------|------------|--------|---------------|--------|
|
|
65
|
+
| 1 | `bundles` | `channel` ASC, `version` DESC, `createdAt` DESC | Get latest bundle by channel | ✅ Exists |
|
|
66
|
+
| 2 | `updateLogs` | `appId` ASC, `timestamp` DESC | App update history | ✅ Exists |
|
|
67
|
+
| 3 | `analytics` | `eventName` ASC, `timestamp` DESC | Analytics by event type | ✅ Exists |
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## Query-to-Index Mapping
|
|
72
|
+
|
|
73
|
+
### Website Frontend Queries
|
|
74
|
+
|
|
75
|
+
#### BuildsPage.tsx (Line 84-103)
|
|
76
|
+
```typescript
|
|
77
|
+
query(buildsRef,
|
|
78
|
+
where('userId', '==', user.uid),
|
|
79
|
+
orderBy('uploadedAt', 'desc'),
|
|
80
|
+
// Optional filters:
|
|
81
|
+
where('appId', '==', filters.appId),
|
|
82
|
+
where('channel', '==', filters.channel),
|
|
83
|
+
where('platform', '==', filters.platform),
|
|
84
|
+
where('status', '==', filters.status)
|
|
85
|
+
)
|
|
86
|
+
```
|
|
87
|
+
**Index Required:** Multiple composite indexes depending on filter combination
|
|
88
|
+
**Index Status:** ✅ Covered by indexes 2-6
|
|
89
|
+
|
|
90
|
+
#### UploadPage.tsx (Line 49-64)
|
|
91
|
+
```typescript
|
|
92
|
+
// Apps query
|
|
93
|
+
query(appsRef, where('userId', '==', user.uid))
|
|
94
|
+
|
|
95
|
+
// Builds query
|
|
96
|
+
query(buildsRef,
|
|
97
|
+
where('userId', '==', user.uid),
|
|
98
|
+
where('uploadedBy', '==', user.uid)
|
|
99
|
+
)
|
|
100
|
+
```
|
|
101
|
+
**Index Required:** Basic userId filter (auto-indexed), uploadedBy needs single-field index
|
|
102
|
+
**Index Status:** ✅ Auto-indexed single field queries
|
|
103
|
+
|
|
104
|
+
#### ConfigPage.tsx (Line 30-32)
|
|
105
|
+
```typescript
|
|
106
|
+
query(appsRef, where('userId', '==', user.uid))
|
|
107
|
+
```
|
|
108
|
+
**Index Required:** Single field userId (auto-indexed)
|
|
109
|
+
**Index Status:** ✅ Auto-indexed
|
|
110
|
+
|
|
111
|
+
#### AnalyticsPage.tsx (Line 101-103)
|
|
112
|
+
```typescript
|
|
113
|
+
query(appsRef, where('userId', '==', user.uid))
|
|
114
|
+
```
|
|
115
|
+
**Index Required:** Single field userId (auto-indexed)
|
|
116
|
+
**Index Status:** ✅ Auto-indexed
|
|
117
|
+
|
|
118
|
+
#### GoogleDrivePage.tsx (Line 42-43)
|
|
119
|
+
```typescript
|
|
120
|
+
doc(db, 'users', user.uid)
|
|
121
|
+
doc(db, 'drive_tokens', userId)
|
|
122
|
+
```
|
|
123
|
+
**Index Required:** None (document reads by ID)
|
|
124
|
+
**Index Status:** ✅ N/A
|
|
125
|
+
|
|
126
|
+
#### SettingsPage.tsx (Line 70-71)
|
|
127
|
+
```typescript
|
|
128
|
+
doc(db, 'users', user.uid)
|
|
129
|
+
```
|
|
130
|
+
**Index Required:** None (document read by ID)
|
|
131
|
+
**Index Status:** ✅ N/A
|
|
132
|
+
|
|
133
|
+
#### RolloutsStore.ts (Line 63)
|
|
134
|
+
```typescript
|
|
135
|
+
query(manifestsRef) // All manifests
|
|
136
|
+
```
|
|
137
|
+
**Index Required:** None (collection scan)
|
|
138
|
+
**Index Status:** ✅ N/A
|
|
139
|
+
|
|
140
|
+
### Website Firebase Functions Queries
|
|
141
|
+
|
|
142
|
+
#### apps.ts (Line 111-115)
|
|
143
|
+
```typescript
|
|
144
|
+
db.collection('apps')
|
|
145
|
+
.where('userId', '==', user.uid)
|
|
146
|
+
.orderBy('createdAt', 'desc')
|
|
147
|
+
```
|
|
148
|
+
**Index Required:** Composite: userId ASC, createdAt DESC
|
|
149
|
+
**Index Status:** ✅ Index #1
|
|
150
|
+
|
|
151
|
+
#### builds.ts (Line 173-176)
|
|
152
|
+
```typescript
|
|
153
|
+
db.collection('builds')
|
|
154
|
+
.where('userId', '==', user.uid)
|
|
155
|
+
.orderBy('createdAt', 'desc')
|
|
156
|
+
// With optional filters for appId, platform, channel
|
|
157
|
+
```
|
|
158
|
+
**Index Required:** Multiple composite indexes
|
|
159
|
+
**Index Status:** ✅ Indexes #2-6
|
|
160
|
+
|
|
161
|
+
#### users.ts (Line 129-137)
|
|
162
|
+
```typescript
|
|
163
|
+
// Apps for user
|
|
164
|
+
db.collection('apps').where('userId', '==', user.uid)
|
|
165
|
+
|
|
166
|
+
// Builds for user
|
|
167
|
+
db.collection('builds').where('userId', '==', user.uid)
|
|
168
|
+
```
|
|
169
|
+
**Index Required:** Single field userId (auto-indexed)
|
|
170
|
+
**Index Status:** ✅ Auto-indexed
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## Missing Indexes Analysis
|
|
175
|
+
|
|
176
|
+
After thorough audit, **NO missing indexes** were identified. All queries are covered by:
|
|
177
|
+
1. Auto-indexed single-field queries
|
|
178
|
+
2. Document ID reads (no index needed)
|
|
179
|
+
3. Composite indexes defined in `firestore.indexes.json`
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## Security Recommendations Implemented
|
|
184
|
+
|
|
185
|
+
1. ✅ All collections have owner-only access rules
|
|
186
|
+
2. ✅ Analytics is write-only from client (prevents data exfiltration)
|
|
187
|
+
3. ✅ Drive tokens stored in separate collection with owner-only access
|
|
188
|
+
4. ✅ Default deny rule prevents unauthorized collection access
|
|
189
|
+
5. ✅ Server-side validation in Firebase Functions
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## Deployment Commands
|
|
194
|
+
|
|
195
|
+
```bash
|
|
196
|
+
# Deploy Firestore indexes
|
|
197
|
+
firebase deploy --only firestore:indexes
|
|
198
|
+
|
|
199
|
+
# Deploy Firestore rules
|
|
200
|
+
firebase deploy --only firestore:rules
|
|
201
|
+
|
|
202
|
+
# Deploy both
|
|
203
|
+
firebase deploy --only firestore
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
## Verification Checklist
|
|
209
|
+
|
|
210
|
+
- [x] All queries mapped to indexes
|
|
211
|
+
- [x] Security rules reviewed
|
|
212
|
+
- [x] Owner checks verified for all collections
|
|
213
|
+
- [x] No missing composite indexes
|
|
214
|
+
- [x] Index files synchronized between root and website
|
|
215
|
+
- [x] Example app has separate indexes for its collections
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
## Last Verification Date
|
|
220
|
+
|
|
221
|
+
**2026-01-16** - Full audit complete, all indexes verified
|