Skip to content

Commit 6dfe2d3

Browse files
committed
Add collection data inspection and test data seeding endpoints
Added two debug endpoints to diagnose and fix the admin dashboard data issues: 1. /api/debug/collection-data - Shows what data actually exists in production collections - Checks users, pages, analytics_events, subscriptions collections - Shows sample data and timestamp formats - Helps identify if collections are empty or have date format issues 2. /api/debug/seed-test-data - Seeds test data for analytics testing - Adds test users, pages, and analytics events with recent timestamps - Only accessible to admin users - Helps verify that analytics pipelines work with real data This will help identify why all dashboard widgets show 'No data available' despite working authentication and collection access.
1 parent 7352051 commit 6dfe2d3

File tree

2 files changed

+376
-0
lines changed

2 files changed

+376
-0
lines changed
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
import { NextRequest, NextResponse } from 'next/server';
2+
import { checkAdminPermissions } from '../../admin-auth-helper';
3+
import { getFirebaseAdmin } from '../../../firebase/firebaseAdmin';
4+
import { getCollectionName } from '../../../utils/environmentConfig';
5+
6+
/**
7+
* Debug endpoint to check what data actually exists in collections
8+
*/
9+
export async function GET(request: NextRequest) {
10+
try {
11+
console.log('[Collection Data] Starting collection data check...');
12+
13+
const testResults = {
14+
timestamp: new Date().toISOString(),
15+
collections: []
16+
};
17+
18+
// Check admin permissions
19+
const adminCheck = await checkAdminPermissions(request);
20+
if (!adminCheck.success) {
21+
return NextResponse.json({
22+
error: 'Admin access required',
23+
details: adminCheck.error
24+
}, { status: 403 });
25+
}
26+
27+
const admin = getFirebaseAdmin();
28+
const db = admin.firestore();
29+
30+
// Check users collection
31+
try {
32+
const usersCollection = getCollectionName('users');
33+
const usersSnapshot = await db.collection(usersCollection)
34+
.orderBy('createdAt', 'desc')
35+
.limit(5)
36+
.get();
37+
38+
const usersData = usersSnapshot.docs.map(doc => ({
39+
id: doc.id,
40+
data: {
41+
email: doc.data().email,
42+
createdAt: doc.data().createdAt?.toDate?.()?.toISOString() || doc.data().createdAt,
43+
username: doc.data().username
44+
}
45+
}));
46+
47+
testResults.collections.push({
48+
name: 'users',
49+
collectionName: usersCollection,
50+
totalDocs: usersSnapshot.size,
51+
sampleData: usersData,
52+
hasCreatedAt: usersData.some(u => u.data.createdAt)
53+
});
54+
} catch (error) {
55+
testResults.collections.push({
56+
name: 'users',
57+
error: error.message
58+
});
59+
}
60+
61+
// Check pages collection
62+
try {
63+
const pagesCollection = getCollectionName('pages');
64+
const pagesSnapshot = await db.collection(pagesCollection)
65+
.orderBy('createdAt', 'desc')
66+
.limit(5)
67+
.get();
68+
69+
const pagesData = pagesSnapshot.docs.map(doc => ({
70+
id: doc.id,
71+
data: {
72+
title: doc.data().title,
73+
createdAt: doc.data().createdAt?.toDate?.()?.toISOString() || doc.data().createdAt,
74+
isPublic: doc.data().isPublic,
75+
authorId: doc.data().authorId
76+
}
77+
}));
78+
79+
testResults.collections.push({
80+
name: 'pages',
81+
collectionName: pagesCollection,
82+
totalDocs: pagesSnapshot.size,
83+
sampleData: pagesData,
84+
hasCreatedAt: pagesData.some(p => p.data.createdAt)
85+
});
86+
} catch (error) {
87+
testResults.collections.push({
88+
name: 'pages',
89+
error: error.message
90+
});
91+
}
92+
93+
// Check analytics_events collection
94+
try {
95+
const analyticsCollection = getCollectionName('analytics_events');
96+
const analyticsSnapshot = await db.collection(analyticsCollection)
97+
.orderBy('timestamp', 'desc')
98+
.limit(10)
99+
.get();
100+
101+
const analyticsData = analyticsSnapshot.docs.map(doc => ({
102+
id: doc.id,
103+
data: {
104+
event: doc.data().event,
105+
timestamp: doc.data().timestamp?.toDate?.()?.toISOString() || doc.data().timestamp,
106+
userId: doc.data().userId,
107+
metadata: doc.data().metadata
108+
}
109+
}));
110+
111+
testResults.collections.push({
112+
name: 'analytics_events',
113+
collectionName: analyticsCollection,
114+
totalDocs: analyticsSnapshot.size,
115+
sampleData: analyticsData,
116+
hasTimestamp: analyticsData.some(a => a.data.timestamp)
117+
});
118+
} catch (error) {
119+
testResults.collections.push({
120+
name: 'analytics_events',
121+
error: error.message
122+
});
123+
}
124+
125+
// Check subscriptions collection
126+
try {
127+
const subscriptionsCollection = getCollectionName('subscriptions');
128+
const subscriptionsSnapshot = await db.collection(subscriptionsCollection)
129+
.orderBy('createdAt', 'desc')
130+
.limit(5)
131+
.get();
132+
133+
const subscriptionsData = subscriptionsSnapshot.docs.map(doc => ({
134+
id: doc.id,
135+
data: {
136+
userId: doc.data().userId,
137+
status: doc.data().status,
138+
createdAt: doc.data().createdAt?.toDate?.()?.toISOString() || doc.data().createdAt,
139+
plan: doc.data().plan
140+
}
141+
}));
142+
143+
testResults.collections.push({
144+
name: 'subscriptions',
145+
collectionName: subscriptionsCollection,
146+
totalDocs: subscriptionsSnapshot.size,
147+
sampleData: subscriptionsData,
148+
hasCreatedAt: subscriptionsData.some(s => s.data.createdAt)
149+
});
150+
} catch (error) {
151+
testResults.collections.push({
152+
name: 'subscriptions',
153+
error: error.message
154+
});
155+
}
156+
157+
// Check date ranges for recent data
158+
const now = new Date();
159+
const sevenDaysAgo = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000);
160+
const thirtyDaysAgo = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000);
161+
162+
testResults.dateRangeInfo = {
163+
now: now.toISOString(),
164+
sevenDaysAgo: sevenDaysAgo.toISOString(),
165+
thirtyDaysAgo: thirtyDaysAgo.toISOString()
166+
};
167+
168+
return NextResponse.json(testResults, {
169+
status: 200,
170+
headers: {
171+
'Cache-Control': 'no-cache, no-store, must-revalidate'
172+
}
173+
});
174+
175+
} catch (error) {
176+
console.error('[Collection Data] Error:', error);
177+
178+
return NextResponse.json({
179+
error: 'Collection data check failed',
180+
details: error instanceof Error ? error.message : 'Unknown error',
181+
timestamp: new Date().toISOString()
182+
}, { status: 500 });
183+
}
184+
}
Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
import { NextRequest, NextResponse } from 'next/server';
2+
import { checkAdminPermissions } from '../../admin-auth-helper';
3+
import { getFirebaseAdmin } from '../../../firebase/firebaseAdmin';
4+
import { getCollectionName } from '../../../utils/environmentConfig';
5+
6+
/**
7+
* Debug endpoint to seed some test data for analytics testing
8+
* ONLY for admin use to test analytics functionality
9+
*/
10+
export async function POST(request: NextRequest) {
11+
try {
12+
console.log('[Seed Test Data] Starting test data seeding...');
13+
14+
// Check admin permissions
15+
const adminCheck = await checkAdminPermissions(request);
16+
if (!adminCheck.success) {
17+
return NextResponse.json({
18+
error: 'Admin access required',
19+
details: adminCheck.error
20+
}, { status: 403 });
21+
}
22+
23+
const admin = getFirebaseAdmin();
24+
const db = admin.firestore();
25+
26+
const results = {
27+
timestamp: new Date().toISOString(),
28+
seeded: []
29+
};
30+
31+
// Seed some test analytics events
32+
const analyticsCollection = getCollectionName('analytics_events');
33+
const now = new Date();
34+
35+
const testEvents = [
36+
{
37+
event: 'user_signup',
38+
timestamp: new Date(now.getTime() - 1 * 24 * 60 * 60 * 1000), // 1 day ago
39+
userId: 'test-user-1',
40+
metadata: { source: 'test-seed' }
41+
},
42+
{
43+
event: 'user_signup',
44+
timestamp: new Date(now.getTime() - 2 * 24 * 60 * 60 * 1000), // 2 days ago
45+
userId: 'test-user-2',
46+
metadata: { source: 'test-seed' }
47+
},
48+
{
49+
event: 'page_created',
50+
timestamp: new Date(now.getTime() - 1 * 24 * 60 * 60 * 1000), // 1 day ago
51+
userId: 'test-user-1',
52+
metadata: {
53+
pageId: 'test-page-1',
54+
isPublic: true,
55+
source: 'test-seed'
56+
}
57+
},
58+
{
59+
event: 'page_created',
60+
timestamp: new Date(now.getTime() - 3 * 24 * 60 * 60 * 1000), // 3 days ago
61+
userId: 'test-user-2',
62+
metadata: {
63+
pageId: 'test-page-2',
64+
isPublic: false,
65+
source: 'test-seed'
66+
}
67+
},
68+
{
69+
event: 'page_shared',
70+
timestamp: new Date(now.getTime() - 2 * 60 * 60 * 1000), // 2 hours ago
71+
userId: 'test-user-1',
72+
metadata: {
73+
pageId: 'test-page-1',
74+
shareMethod: 'link',
75+
source: 'test-seed'
76+
}
77+
}
78+
];
79+
80+
// Add analytics events
81+
for (const event of testEvents) {
82+
try {
83+
const docRef = await db.collection(analyticsCollection).add(event);
84+
results.seeded.push({
85+
type: 'analytics_event',
86+
id: docRef.id,
87+
event: event.event,
88+
timestamp: event.timestamp.toISOString()
89+
});
90+
} catch (error) {
91+
results.seeded.push({
92+
type: 'analytics_event',
93+
error: error.message,
94+
event: event.event
95+
});
96+
}
97+
}
98+
99+
// Seed some test users (with recent createdAt)
100+
const usersCollection = getCollectionName('users');
101+
const testUsers = [
102+
{
103+
email: 'test-user-1@example.com',
104+
username: 'testuser1',
105+
createdAt: new Date(now.getTime() - 1 * 24 * 60 * 60 * 1000), // 1 day ago
106+
isTestData: true
107+
},
108+
{
109+
email: 'test-user-2@example.com',
110+
username: 'testuser2',
111+
createdAt: new Date(now.getTime() - 2 * 24 * 60 * 60 * 1000), // 2 days ago
112+
isTestData: true
113+
}
114+
];
115+
116+
for (const user of testUsers) {
117+
try {
118+
const docRef = await db.collection(usersCollection).add(user);
119+
results.seeded.push({
120+
type: 'user',
121+
id: docRef.id,
122+
email: user.email,
123+
createdAt: user.createdAt.toISOString()
124+
});
125+
} catch (error) {
126+
results.seeded.push({
127+
type: 'user',
128+
error: error.message,
129+
email: user.email
130+
});
131+
}
132+
}
133+
134+
// Seed some test pages
135+
const pagesCollection = getCollectionName('pages');
136+
const testPages = [
137+
{
138+
title: 'Test Page 1',
139+
content: 'This is test content for analytics testing',
140+
authorId: 'test-user-1',
141+
isPublic: true,
142+
createdAt: new Date(now.getTime() - 1 * 24 * 60 * 60 * 1000), // 1 day ago
143+
isTestData: true
144+
},
145+
{
146+
title: 'Test Page 2',
147+
content: 'This is private test content',
148+
authorId: 'test-user-2',
149+
isPublic: false,
150+
createdAt: new Date(now.getTime() - 3 * 24 * 60 * 60 * 1000), // 3 days ago
151+
isTestData: true
152+
}
153+
];
154+
155+
for (const page of testPages) {
156+
try {
157+
const docRef = await db.collection(pagesCollection).add(page);
158+
results.seeded.push({
159+
type: 'page',
160+
id: docRef.id,
161+
title: page.title,
162+
isPublic: page.isPublic,
163+
createdAt: page.createdAt.toISOString()
164+
});
165+
} catch (error) {
166+
results.seeded.push({
167+
type: 'page',
168+
error: error.message,
169+
title: page.title
170+
});
171+
}
172+
}
173+
174+
console.log('[Seed Test Data] Seeded', results.seeded.length, 'test records');
175+
176+
return NextResponse.json(results, {
177+
status: 200,
178+
headers: {
179+
'Cache-Control': 'no-cache, no-store, must-revalidate'
180+
}
181+
});
182+
183+
} catch (error) {
184+
console.error('[Seed Test Data] Error:', error);
185+
186+
return NextResponse.json({
187+
error: 'Test data seeding failed',
188+
details: error instanceof Error ? error.message : 'Unknown error',
189+
timestamp: new Date().toISOString()
190+
}, { status: 500 });
191+
}
192+
}

0 commit comments

Comments
 (0)