Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
VITE_FIREBASE_API_KEY=
VITE_FIREBASE_AUTH_DOMAIN=
VITE_FIREBASE_PROJECT_ID=startupsindia-mediaplatform
VITE_FIREBASE_STORAGE_BUCKET=
VITE_FIREBASE_MESSAGING_SENDER_ID=
VITE_FIREBASE_APP_ID=
VITE_FIREBASE_MEASUREMENT_ID=
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
node_modules/
dist/
.vscode/
.env
.env.*
!.env.example
.DS_Store
8 changes: 8 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"dart.analysisExcludedFolders": [
"reference_files"
],
"search.exclude": {
"reference_files": true
}
}
157 changes: 157 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
# Admin Panel Handoff

This folder contains reference files from the Flutter app for building a separate admin web project against the same Firebase project.

The admin panel should not import these Dart files directly unless it is also a Dart/Flutter project. For a React, Next.js, or other web admin project, use them as the source of truth for Firestore collection names, document fields, and expected app behavior.

## Firebase Project

- Project ID: `startupsindia-mediaplatform`
- Auth domain: `startupsindia-mediaplatform.firebaseapp.com`
- Storage bucket: `startupsindia-mediaplatform.firebasestorage.app`

Use the same Firebase project in the admin web app.

## Reference Files

- `reference_files/firestore_repository.dart`
- Shows current Firestore collection names and operations.
- Current collections: `users`, `articles`, `user_topics`, `users/{uid}/notifications`.
- Includes article create/read/search, like/bookmark toggles, user profile save, topic follow/unfollow, and Cloudinary image upload.

- `reference_files/news_article_model.dart`
- Source of truth for current `articles/{articleId}` document fields.

- `reference_files/user_model.dart`
- Source of truth for current `users/{uid}` document fields.

- `reference_files/app_notification.dart`
- Source of truth for `users/{uid}/notifications/{notificationId}` fields.

- `reference_files/home_mock_data.dart`
- Shows the home modules that should eventually become admin-managed collections: featured stories, events, courses, communities, leaderboard, and funding cards.

## Current Firestore Schemas

### `articles/{articleId}`

```ts
{
authorId: string,
category: string,
headline: string,
sourceName: string,
sourceId: string,
sourceLogoAsset: string,
thumbnailAsset: string,
timeAgo: string,
body: string,
likesCount: number,
commentsCount: number,
isSourceFollowing: boolean,
isBookmarked: boolean,
isLiked: boolean,
isTrending: boolean,
likedBy: string[],
bookmarkedBy: string[],
createdAt: Timestamp,
updatedAt: Timestamp
}
```

Admin panel should add moderation/status fields:

```ts
{
status: "draft" | "pending" | "published" | "rejected" | "archived",
publishedAt: Timestamp | null,
reviewedBy: string | null,
reviewedAt: Timestamp | null,
rejectionReason: string
}
```

### `users/{uid}`

```ts
{
uid: string,
username: string,
fullName: string,
email: string,
phone: string,
displayName: string,
bio: string,
avatarUrl: string,
websiteUrl: string,
followersCount: number,
followingCount: number,
newsCount: number,
role: string,
interests: string[],
onboardingCompleted: boolean,
fcmTokens: string[],
updatedAt: Timestamp
}
```

Admin panel should add admin/account fields:

```ts
{
accountStatus: "active" | "suspended" | "deleted",
adminRole: "user" | "author" | "moderator" | "admin",
isVerified: boolean,
createdAt: Timestamp,
lastLoginAt: Timestamp
}
```

### `user_topics/{uid}`

```ts
{
topics: string[],
updatedAt: Timestamp
}
```

### `users/{uid}/notifications/{notificationId}`

```ts
{
type: "news" | "follow" | "interaction",
title: string,
subtitle: string,
createdAt: Timestamp,
avatarLabel: string,
isRead: boolean,
payload: string | null
}
```

## Admin Modules To Build

1. Admin auth and access guard
2. Articles CMS
3. Article moderation queue
4. User management
5. Topics/categories management
6. Sources/authors management
7. Notification campaigns
8. Comments moderation
9. Home modules CMS:
- Featured stories
- Funding opportunities
- Events
- Courses
- Communities
- Startup leaderboard

## Security Notes

- Do not trust client-side checks for admin access.
- Prefer Firebase Auth custom claims like `admin: true`.
- Alternatively, use a locked `admin_users/{uid}` collection.
- Sending push notifications must happen through Firebase Admin SDK, Cloud Functions, or a server route. Do not send FCM from the browser client SDK.

2 changes: 2 additions & 0 deletions firebase-admin-scripts/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
serviceAccountKey.json
node_modules/
26 changes: 26 additions & 0 deletions firebase-admin-scripts/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Firebase admin scripts

This folder is excluded from sensitive files by .gitignore.

## Setup

1) Copy your service account key file here and name it:

```
serviceAccountKey.json
```

2) Install dependencies:

```
npm init -y
npm install firebase-admin
```

3) Run the script:

```
node setAdmin.js
```

Do not commit the service account key.
26 changes: 26 additions & 0 deletions firebase-admin-scripts/setAdmin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
const admin = require("firebase-admin");

const serviceAccount = require("./serviceAccountKey.json");

admin.initializeApp({
credential: admin.credential.cert(serviceAccount)
});

const uid = "dbIZyFkKffXNurjPApZX15kaRx42";

async function setAdminClaim() {
try {
await admin.auth().setCustomUserClaims(uid, {
admin: true,
role: "admin"
});

console.log("Admin claim added successfully for:", uid);
process.exit(0);
} catch (error) {
console.error("Error setting admin claim:", error);
process.exit(1);
}
}

setAdminClaim();
26 changes: 26 additions & 0 deletions fix_services.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
const fs = require('fs');
const path = require('path');

const servicesDir = path.join(__dirname, 'src', 'services');

const files = fs.readdirSync(servicesDir);

files.forEach(file => {
if (file.endsWith('.ts')) {
const filePath = path.join(servicesDir, file);
let content = fs.readFileSync(filePath, 'utf8');

// Replace { id: item.id, ...(item.data() as Article) }
// with { ...(item.data() as Article), id: item.id }
content = content.replace(/\{\s*id:\s*([^,]+),\s*\.\.\.([^}]+)\}/g, '{ ...$2, id: $1 }');

// Same for uid
content = content.replace(/\{\s*uid:\s*([^,]+),\s*\.\.\.([^}]+)\}/g, '{ ...$2, uid: $1 }');

// Same for slug
content = content.replace(/\{\s*slug:\s*([^,]+),\s*\.\.\.([^}]+)\}/g, '{ ...$2, slug: $1 }');

fs.writeFileSync(filePath, content);
}
});
console.log('Services fixed');
19 changes: 19 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Startups India Admin</title>
<link rel="icon" href="/favicon.svg" type="image/svg+xml" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&family=Newsreader:wght@400;500;600&display=swap"
rel="stylesheet"
/>
</head>
<body class="min-h-screen bg-background text-foreground">
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
Loading