@ma7moudsalama/falak-app 1.0.0

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.
Files changed (37) hide show
  1. package/README.md +378 -0
  2. package/bin/falak.js +157 -0
  3. package/index.js +5 -0
  4. package/lib/scaffold.js +23 -0
  5. package/package.json +46 -0
  6. package/template/_env.example +34 -0
  7. package/template/_gitignore +8 -0
  8. package/template/firebase-rules.json +36 -0
  9. package/template/index.html +21 -0
  10. package/template/package.json +36 -0
  11. package/template/postcss.config.js +6 -0
  12. package/template/public/favicon.svg +5 -0
  13. package/template/src/App.vue +95 -0
  14. package/template/src/assets/main.css +100 -0
  15. package/template/src/components/layout/AppLayout.vue +163 -0
  16. package/template/src/composables/useAuth.js +393 -0
  17. package/template/src/composables/useCrypto.js +153 -0
  18. package/template/src/composables/useDatabase.js +341 -0
  19. package/template/src/composables/useGroq.js +237 -0
  20. package/template/src/composables/usePaymob.js +392 -0
  21. package/template/src/firebase/index.js +87 -0
  22. package/template/src/i18n/index.js +66 -0
  23. package/template/src/i18n/locales/ar.json +121 -0
  24. package/template/src/i18n/locales/en.json +121 -0
  25. package/template/src/main.js +59 -0
  26. package/template/src/router/index.js +127 -0
  27. package/template/src/stores/auth.js +14 -0
  28. package/template/src/views/AdminView.vue +67 -0
  29. package/template/src/views/DashboardView.vue +253 -0
  30. package/template/src/views/HomeView.vue +13 -0
  31. package/template/src/views/NotFoundView.vue +8 -0
  32. package/template/src/views/ProfileView.vue +134 -0
  33. package/template/src/views/auth/ForgotView.vue +57 -0
  34. package/template/src/views/auth/LoginView.vue +169 -0
  35. package/template/src/views/auth/RegisterView.vue +103 -0
  36. package/template/tailwind.config.js +41 -0
  37. package/template/vite.config.js +29 -0
package/README.md ADDED
@@ -0,0 +1,378 @@
1
+ # فَلَك · Falak App
2
+
3
+ > **Production-ready Vue 3 boilerplate** with Firebase, PrimeVue, Tailwind CSS, i18n (Arabic + English), Groq AI, Paymob payments, offline IndexedDB sync, and AES encryption — all wired up and ready to build on.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/falak-app)](https://npmjs.com/package/falak-app)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
7
+
8
+ ---
9
+
10
+ ## Quick Start
11
+
12
+ ```bash
13
+ # Scaffold a new project
14
+ npx falak-app create my-project
15
+
16
+ # Or install globally
17
+ npm i -g falak-app
18
+ falak create my-project
19
+
20
+ # Then
21
+ cd my-project
22
+ cp .env.example .env # fill in your keys
23
+ npm run dev
24
+ ```
25
+
26
+ ---
27
+
28
+ ## What's Inside
29
+
30
+ | Layer | Package | Status |
31
+ |---|---|---|
32
+ | Framework | Vue 3 + Vite | ✅ Configured |
33
+ | UI Library | PrimeVue 4 (Aura theme) | ✅ Configured |
34
+ | Styling | Tailwind CSS 3 | ✅ Configured |
35
+ | State | Pinia | ✅ Configured |
36
+ | Routing | Vue Router 4 | ✅ Configured + guards |
37
+ | Translation | Vue I18n 10 (EN + AR/RTL) | ✅ Configured |
38
+ | Auth | Firebase Auth (Email, Google, Facebook) | ✅ Composable ready |
39
+ | Database | Firebase Realtime DB | ✅ Composable ready |
40
+ | Offline | IndexedDB via `idb` | ✅ Auto-sync |
41
+ | Encryption | AES-256 via `crypto-js` | ✅ Composable ready |
42
+ | AI | Groq SDK (LLaMA 3.3) | ✅ Composable ready |
43
+ | Payments | Paymob | ✅ Composable + subscriptions |
44
+
45
+ ---
46
+
47
+ ## Project Structure
48
+
49
+ ```
50
+ src/
51
+ ├── assets/
52
+ │ └── main.css ← Tailwind + custom utilities
53
+ ├── components/
54
+ │ └── layout/
55
+ │ └── AppLayout.vue ← Sidebar + topbar layout shell
56
+ ├── composables/
57
+ │ ├── useAuth.js ← Firebase auth + roles + sessions
58
+ │ ├── useDatabase.js ← RTDB + IndexedDB offline manager
59
+ │ ├── useCrypto.js ← AES encrypt/decrypt
60
+ │ ├── useGroq.js ← Groq AI chat + streaming
61
+ │ └── usePaymob.js ← Paymob payments + subscriptions
62
+ ├── firebase/
63
+ │ └── index.js ← Firebase app init + all services
64
+ ├── i18n/
65
+ │ ├── index.js ← Vue I18n setup + locale switcher
66
+ │ └── locales/
67
+ │ ├── en.json
68
+ │ └── ar.json
69
+ ├── router/
70
+ │ └── index.js ← Routes + auth/role guards
71
+ ├── stores/
72
+ │ └── auth.js ← Pinia wrapper for useAuth
73
+ ├── views/
74
+ │ ├── auth/
75
+ │ │ ├── LoginView.vue
76
+ │ │ ├── RegisterView.vue
77
+ │ │ └── ForgotView.vue
78
+ │ ├── HomeView.vue
79
+ │ ├── DashboardView.vue ← Live data + AI + subscription demo
80
+ │ ├── ProfileView.vue
81
+ │ ├── AdminView.vue
82
+ │ └── NotFoundView.vue
83
+ ├── App.vue
84
+ └── main.js
85
+ ```
86
+
87
+ ---
88
+
89
+ ## Configuration
90
+
91
+ ### 1. Firebase
92
+
93
+ Edit `src/firebase/index.js` or set your `.env`:
94
+
95
+ ```env
96
+ VITE_FIREBASE_API_KEY=...
97
+ VITE_FIREBASE_AUTH_DOMAIN=...
98
+ VITE_FIREBASE_DATABASE_URL=...
99
+ VITE_FIREBASE_PROJECT_ID=...
100
+ VITE_FIREBASE_STORAGE_BUCKET=...
101
+ VITE_FIREBASE_MESSAGING_SENDER_ID=...
102
+ VITE_FIREBASE_APP_ID=...
103
+ ```
104
+
105
+ Enable in Firebase Console:
106
+ - Authentication → Email/Password, Google, Facebook
107
+ - Realtime Database → create database
108
+ - Upload `firebase-rules.json` as your security rules
109
+
110
+ ### 2. Groq AI
111
+
112
+ ```env
113
+ VITE_GROQ_API_KEY=gsk_...
114
+ VITE_GROQ_MODEL=llama-3.3-70b-versatile
115
+ ```
116
+
117
+ Get your key at [console.groq.com](https://console.groq.com).
118
+
119
+ ### 3. Paymob
120
+
121
+ ```env
122
+ VITE_PAYMOB_API_KEY=...
123
+ VITE_PAYMOB_INTEGRATION_ID=...
124
+ VITE_PAYMOB_IFRAME_ID=...
125
+ VITE_PAYMOB_HMAC_SECRET=...
126
+ ```
127
+
128
+ Get credentials from [accept.paymob.com](https://accept.paymob.com).
129
+
130
+ ### 4. Encryption
131
+
132
+ ```env
133
+ VITE_ENCRYPTION_KEY=your_strong_random_secret
134
+ ```
135
+
136
+ ---
137
+
138
+ ## Composables API
139
+
140
+ ### `useAuth()`
141
+
142
+ ```js
143
+ import { useAuth } from '@/composables/useAuth.js'
144
+
145
+ const {
146
+ currentUser, // Ref<FirebaseUser | null>
147
+ userProfile, // Ref<Object> — RTDB profile
148
+ userRole, // Ref<string> — live from RTDB
149
+ isAuthenticated, // ComputedRef<bool>
150
+ isAdmin, // ComputedRef<bool>
151
+ isSuperAdmin, // ComputedRef<bool>
152
+ isAuthReady, // Ref<bool> — true after first auth check
153
+ isLoading, // Ref<bool>
154
+ authError, // Ref<string | null>
155
+
156
+ register, // ({ email, password, displayName }) → { success, user }
157
+ login, // ({ email, password }) → { success, user }
158
+ logout, // → { success }
159
+ resetPassword, // (email) → { success }
160
+ changePassword, // ({ currentPassword, newPassword }) → { success }
161
+ loginWithGoogle, // (useRedirect?) → { success, user }
162
+ loginWithFacebook,// (useRedirect?) → { success, user }
163
+ updateUserProfile,// (data) → { success }
164
+ setUserRole, // (uid, role) → { success } ← admin only
165
+ deleteAccount, // → { success }
166
+ hasPermission, // (permission) → bool
167
+ hasRole, // (...roles) → bool
168
+ ROLES // { SUPER_ADMIN, ADMIN, USER, GUEST }
169
+ } = useAuth()
170
+ ```
171
+
172
+ **User roles** are stored in `/users/{uid}/role` in RTDB and listened to in real-time.
173
+ **Session data** (online, lastSeen) is written to `/sessions/{uid}` with `onDisconnect` handling.
174
+
175
+ ---
176
+
177
+ ### `useDatabase(options?)`
178
+
179
+ ```js
180
+ import { useDatabase } from '@/composables/useDatabase.js'
181
+
182
+ const db = useDatabase({
183
+ encryptedPaths: ['payments/*'], // paths to auto-encrypt
184
+ encryptFields: ['ssn', 'card'] // field names to encrypt
185
+ })
186
+
187
+ // One-time read (offline-aware)
188
+ const user = await db.get('users/uid123')
189
+
190
+ // Write (blocked offline with error)
191
+ await db.set('todos/1', { text: 'Buy milk', done: false })
192
+ await db.update('todos/1', { done: true })
193
+ await db.push('todos', { text: 'New item' }) // → { success, key }
194
+ await db.remove('todos/1')
195
+
196
+ // Real-time listener (reactive ref + IDB sync)
197
+ const { data, unsubscribe } = db.listen('todos')
198
+ // data.value updates live
199
+
200
+ // Real-time child events (efficient for large lists)
201
+ const { items, unsubscribe } = db.listenList('messages')
202
+ // items.value = { key1: {...}, key2: {...} }
203
+
204
+ // Offline-only reads
205
+ const cached = await db.getOffline('todos')
206
+ const all = await db.getAllOffline('todos')
207
+
208
+ // Network status
209
+ db.isOnline // Ref<bool>
210
+ ```
211
+
212
+ **Offline behavior:**
213
+ - All write operations return `{ success: false, error: 'You are offline. Data is read-only.' }` when offline.
214
+ - Read operations return IndexedDB cached data.
215
+ - Remote changes are auto-synced to IDB when online.
216
+
217
+ ---
218
+
219
+ ### `useCrypto()`
220
+
221
+ ```js
222
+ import { useCrypto } from '@/composables/useCrypto.js'
223
+
224
+ const { encrypt, decrypt, encryptObject, decryptObject,
225
+ encryptFields, decryptFields, hash, hmac, randomToken } = useCrypto()
226
+
227
+ const cipher = encrypt('sensitive data')
228
+ const plain = decrypt(cipher)
229
+
230
+ const encObj = encryptObject({ ssn: '123-45-6789', name: 'Max' })
231
+ const obj = decryptObject(encObj)
232
+
233
+ // Encrypt only specific fields
234
+ const safe = encryptFields(userData, ['ssn', 'bankAccount'])
235
+ const back = decryptFields(safe, ['ssn', 'bankAccount'])
236
+
237
+ // SHA256 hash
238
+ const hashed = hash('mypassword')
239
+
240
+ // HMAC (used by Paymob webhook verification)
241
+ const sig = hmac('message', 'secret')
242
+ ```
243
+
244
+ ---
245
+
246
+ ### `useGroq(systemPrompt?)`
247
+
248
+ ```js
249
+ import { useGroq } from '@/composables/useGroq.js'
250
+
251
+ const groq = useGroq('You are a helpful assistant.')
252
+
253
+ // Single prompt
254
+ const reply = await groq.chat('What is Vue.js?')
255
+
256
+ // Streaming
257
+ await groq.streamChat('Tell me a story', (chunk, full) => {
258
+ output.value = full
259
+ })
260
+
261
+ // Multi-turn conversation
262
+ await groq.sendConversation('Hello!')
263
+ await groq.sendConversation('What did I just say?')
264
+
265
+ // Streaming multi-turn
266
+ await groq.streamConversation('Continue...', (chunk) => { ... })
267
+
268
+ // Audio transcription (Whisper)
269
+ const text = await groq.transcribe(audioBlob, 'ar')
270
+
271
+ groq.clearConversation()
272
+ groq.setSystemPrompt('New system prompt')
273
+ ```
274
+
275
+ ---
276
+
277
+ ### `usePaymob()` + `useSubscription()`
278
+
279
+ ```js
280
+ import { usePaymob, useSubscription, PLANS } from '@/composables/usePaymob.js'
281
+
282
+ // ── Payments ──
283
+ const paymob = usePaymob()
284
+
285
+ // Full payment flow → opens iframe URL
286
+ const result = await paymob.initPayment({
287
+ amountCents: 14900, // 149.00 EGP
288
+ currency: 'EGP',
289
+ billingData: { ... }
290
+ })
291
+ // result.iframeUrl → embed or open
292
+
293
+ // Open in new tab
294
+ await paymob.openPaymentTab({ amountCents: 14900, ... })
295
+
296
+ // Verify Paymob webhook HMAC
297
+ const valid = paymob.verifyHmac(callbackData)
298
+
299
+ // ── Subscriptions ──
300
+ const sub = useSubscription()
301
+
302
+ // Initialize free plan for new users
303
+ await sub.initFreeplan(userId)
304
+
305
+ // Activate after successful payment
306
+ await sub.activateSubscription(userId, 'PRO', { paymobOrderId: 12345, amountCents: 14900 })
307
+
308
+ // Real-time subscription listener
309
+ const { data } = sub.listenSubscription(userId)
310
+ // data.value = { planId, status, expiresAt, features, ... }
311
+
312
+ // Feature gating
313
+ const canUseAPI = await sub.hasFeature(userId, 'api_access')
314
+ const active = await sub.isActive(userId)
315
+
316
+ await sub.cancelSubscription(userId)
317
+ ```
318
+
319
+ **Subscription data in RTDB** (`/subscriptions/{uid}`):
320
+ ```json
321
+ {
322
+ "planId": "pro",
323
+ "planName": "Pro",
324
+ "status": "active",
325
+ "features": ["read", "write", "advanced_features", "api_access"],
326
+ "startedAt": 1700000000000,
327
+ "expiresAt": 1702592000000,
328
+ "autoRenew": true,
329
+ "paymentHistory": [{ "paidAt": 1700000000000, "amountCents": 14900 }]
330
+ }
331
+ ```
332
+
333
+ ---
334
+
335
+ ## i18n
336
+
337
+ ```js
338
+ import { setLocale } from '@/i18n/index.js'
339
+
340
+ setLocale('ar') // switches to Arabic + sets dir="rtl"
341
+ setLocale('en') // switches to English + sets dir="ltr"
342
+ ```
343
+
344
+ In templates:
345
+ ```vue
346
+ <p>{{ $t('auth.email') }}</p>
347
+ <p>{{ $d(date, 'short') }}</p>
348
+ <p>{{ $n(149, 'egp') }}</p>
349
+ ```
350
+
351
+ To add a new language, add its locale file to `src/i18n/locales/` and register it in `src/i18n/index.js`.
352
+
353
+ ---
354
+
355
+ ## Security Rules
356
+
357
+ Upload `firebase-rules.json` to your Firebase Realtime Database rules:
358
+
359
+ ```
360
+ Firebase Console → Realtime Database → Rules → paste contents
361
+ ```
362
+
363
+ ---
364
+
365
+ ## Scripts
366
+
367
+ ```bash
368
+ npm run dev # Start dev server (http://localhost:5173)
369
+ npm run build # Production build → dist/
370
+ npm run preview # Preview production build
371
+ npm run lint # Lint + auto-fix
372
+ ```
373
+
374
+ ---
375
+
376
+ ## License
377
+
378
+ MIT © Falak App
package/bin/falak.js ADDED
@@ -0,0 +1,157 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { program } from 'commander'
4
+ import chalk from 'chalk'
5
+ import inquirer from 'inquirer'
6
+ import ora from 'ora'
7
+ import fs from 'fs-extra'
8
+ import path from 'path'
9
+ import { fileURLToPath } from 'url'
10
+ import { execSync } from 'child_process'
11
+
12
+ const __filename = fileURLToPath(import.meta.url)
13
+ const __dirname = path.dirname(__filename)
14
+
15
+ const TEMPLATE_DIR = path.join(__dirname, '..', 'template')
16
+
17
+ const banner = `
18
+ ${chalk.cyan('███████╗ █████╗ ██╗ █████╗ ██╗ ██╗')}
19
+ ${chalk.cyan('██╔════╝██╔══██╗██║ ██╔══██╗██║ ██╔╝')}
20
+ ${chalk.cyan('█████╗ ███████║██║ ███████║█████╔╝ ')}
21
+ ${chalk.cyan('██╔══╝ ██╔══██║██║ ██╔══██║██╔═██╗ ')}
22
+ ${chalk.cyan('██║ ██║ ██║███████╗██║ ██║██║ ██╗')}
23
+ ${chalk.cyan('╚═╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝')}
24
+ ${chalk.gray('Vue 3 Production Boilerplate — فلك')}
25
+ `
26
+
27
+ program
28
+ .name('falak-app')
29
+ .description('Create a new Falak Vue 3 project')
30
+ .version('1.0.0')
31
+
32
+ program
33
+ .command('create [project-name]')
34
+ .alias('c')
35
+ .description('Scaffold a new Falak project')
36
+ .option('--no-install', 'Skip npm install')
37
+ .action(async (projectName, options) => {
38
+ console.log(banner)
39
+
40
+ const answers = await inquirer.prompt([
41
+ {
42
+ type: 'input',
43
+ name: 'name',
44
+ message: 'Project name:',
45
+ default: projectName || 'my-falak-app',
46
+ when: !projectName,
47
+ validate: (v) => /^[a-z0-9-_]+$/.test(v) || 'Use lowercase letters, numbers, hyphens only'
48
+ },
49
+ {
50
+ type: 'input',
51
+ name: 'displayName',
52
+ message: 'App display name:',
53
+ default: (a) => (a.name || projectName || 'My App')
54
+ },
55
+ {
56
+ type: 'confirm',
57
+ name: 'arabic',
58
+ message: 'Enable Arabic (RTL) locale by default?',
59
+ default: false
60
+ }
61
+ ])
62
+
63
+ const name = projectName || answers.name
64
+ const targetDir = path.resolve(process.cwd(), name)
65
+
66
+ if (fs.existsSync(targetDir)) {
67
+ const { overwrite } = await inquirer.prompt([{
68
+ type: 'confirm',
69
+ name: 'overwrite',
70
+ message: `Directory "${name}" already exists. Overwrite?`,
71
+ default: false
72
+ }])
73
+ if (!overwrite) {
74
+ console.log(chalk.red('Aborted.'))
75
+ process.exit(1)
76
+ }
77
+ fs.removeSync(targetDir)
78
+ }
79
+
80
+ const spinner = ora('Scaffolding project...').start()
81
+
82
+ try {
83
+ // Copy template
84
+ fs.copySync(TEMPLATE_DIR, targetDir)
85
+
86
+ // Update package.json with project name
87
+ const pkgPath = path.join(targetDir, 'package.json')
88
+ const pkg = fs.readJsonSync(pkgPath)
89
+ pkg.name = name
90
+ fs.writeJsonSync(pkgPath, pkg, { spaces: 2 })
91
+
92
+ // Update index.html title
93
+ const htmlPath = path.join(targetDir, 'index.html')
94
+ let html = fs.readFileSync(htmlPath, 'utf-8')
95
+ html = html.replace('__APP_NAME__', answers.displayName || name)
96
+ fs.writeFileSync(htmlPath, html)
97
+
98
+ // Rename _gitignore → .gitignore
99
+ const gitignoreSrc = path.join(targetDir, '_gitignore')
100
+ if (fs.existsSync(gitignoreSrc)) {
101
+ fs.moveSync(gitignoreSrc, path.join(targetDir, '.gitignore'))
102
+ }
103
+
104
+ // Rename _env.example → .env.example
105
+ const envSrc = path.join(targetDir, '_env.example')
106
+ if (fs.existsSync(envSrc)) {
107
+ fs.moveSync(envSrc, path.join(targetDir, '.env.example'))
108
+ fs.copySync(path.join(targetDir, '.env.example'), path.join(targetDir, '.env'))
109
+ }
110
+
111
+ spinner.succeed(chalk.green('Project scaffolded successfully!'))
112
+
113
+ if (options.install !== false) {
114
+ const installSpinner = ora('Installing dependencies...').start()
115
+ try {
116
+ execSync('npm install', { cwd: targetDir, stdio: 'ignore' })
117
+ installSpinner.succeed(chalk.green('Dependencies installed!'))
118
+ } catch {
119
+ installSpinner.warn(chalk.yellow('Auto-install failed. Run "npm install" manually.'))
120
+ }
121
+ }
122
+
123
+ console.log(`
124
+ ${chalk.bold('✅ Falak project ready!')}
125
+
126
+ ${chalk.cyan('Next steps:')}
127
+ ${chalk.gray('$')} cd ${name}
128
+ ${chalk.gray('$')} cp .env.example .env ${chalk.gray('# fill in your keys')}
129
+ ${chalk.gray('$')} npm run dev
130
+
131
+ ${chalk.cyan('Configure your services in:')}
132
+ ${chalk.yellow('src/firebase/index.js')} — Firebase credentials
133
+ ${chalk.yellow('src/config/groq.js')} — Groq API key
134
+ ${chalk.yellow('src/config/paymob.js')} — Paymob credentials
135
+ ${chalk.yellow('src/i18n/index.js')} — Add languages
136
+
137
+ ${chalk.gray('Docs: https://github.com/falak-app/falak-app')}
138
+ `)
139
+ } catch (err) {
140
+ spinner.fail(chalk.red('Scaffolding failed'))
141
+ console.error(err)
142
+ process.exit(1)
143
+ }
144
+ })
145
+
146
+ // Default: if no sub-command, run create
147
+ program
148
+ .argument('[project-name]')
149
+ .action(async (projectName) => {
150
+ if (projectName) {
151
+ program.parse(['node', 'falak', 'create', projectName])
152
+ } else {
153
+ program.parse(['node', 'falak', 'create'])
154
+ }
155
+ })
156
+
157
+ program.parse()
package/index.js ADDED
@@ -0,0 +1,5 @@
1
+ // Falak App — programmatic API
2
+ // Use the CLI: npx falak-app create my-project
3
+ // Or import scaffold() in your own tooling
4
+
5
+ export { scaffold } from './lib/scaffold.js'
@@ -0,0 +1,23 @@
1
+ import fs from 'fs-extra'
2
+ import path from 'path'
3
+ import { fileURLToPath } from 'url'
4
+
5
+ const __dirname = path.dirname(fileURLToPath(import.meta.url))
6
+ const TEMPLATE = path.join(__dirname, '..', 'template')
7
+
8
+ export async function scaffold(targetDir, options = {}) {
9
+ fs.copySync(TEMPLATE, targetDir)
10
+ if (options.name) {
11
+ const pkgPath = path.join(targetDir, 'package.json')
12
+ const pkg = fs.readJsonSync(pkgPath)
13
+ pkg.name = options.name
14
+ fs.writeJsonSync(pkgPath, pkg, { spaces: 2 })
15
+ }
16
+ const gitignoreSrc = path.join(targetDir, '_gitignore')
17
+ if (fs.existsSync(gitignoreSrc)) fs.moveSync(gitignoreSrc, path.join(targetDir, '.gitignore'))
18
+ const envSrc = path.join(targetDir, '_env.example')
19
+ if (fs.existsSync(envSrc)) {
20
+ fs.moveSync(envSrc, path.join(targetDir, '.env.example'))
21
+ fs.copySync(path.join(targetDir, '.env.example'), path.join(targetDir, '.env'))
22
+ }
23
+ }
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@ma7moudsalama/falak-app",
3
+ "version": "1.0.0",
4
+ "description": "Production-ready Vue 3 boilerplate with Firebase, PrimeVue, Tailwind, i18n, Groq AI, Paymob & more",
5
+ "keywords": [
6
+ "vue",
7
+ "vue3",
8
+ "boilerplate",
9
+ "firebase",
10
+ "primevue",
11
+ "tailwind",
12
+ "groq",
13
+ "paymob",
14
+ "starter",
15
+ "template"
16
+ ],
17
+ "author": "MA7MOUD SALAMA <mahmoudsalamacoder@gmail.com>",
18
+ "license": "MIT",
19
+ "bin": {
20
+ "falak-app": "./bin/falak.js",
21
+ "falak": "./bin/falak.js"
22
+ },
23
+ "main": "index.js",
24
+ "files": [
25
+ "bin",
26
+ "template",
27
+ "lib",
28
+ "index.js",
29
+ "README.md"
30
+ ],
31
+ "dependencies": {
32
+ "chalk": "^5.3.0",
33
+ "commander": "^12.0.0",
34
+ "fs-extra": "^11.2.0",
35
+ "inquirer": "^9.2.15",
36
+ "ora": "^8.0.1"
37
+ },
38
+ "engines": {
39
+ "node": ">=18.0.0"
40
+ },
41
+ "repository": {
42
+ "type": "git",
43
+ "url": "https://github.com/ma7moudsalamacoder/falak-app"
44
+ },
45
+ "type": "module"
46
+ }
@@ -0,0 +1,34 @@
1
+ # ──────────────────────────────────────────────
2
+ # Falak App — Environment Variables
3
+ # Copy this file to .env and fill in your values
4
+ # ──────────────────────────────────────────────
5
+
6
+ # Firebase Configuration
7
+ VITE_FIREBASE_API_KEY=your_firebase_api_key
8
+ VITE_FIREBASE_AUTH_DOMAIN=your_project.firebaseapp.com
9
+ VITE_FIREBASE_DATABASE_URL=https://your_project-default-rtdb.firebaseio.com
10
+ VITE_FIREBASE_PROJECT_ID=your_project_id
11
+ VITE_FIREBASE_STORAGE_BUCKET=your_project.appspot.com
12
+ VITE_FIREBASE_MESSAGING_SENDER_ID=your_sender_id
13
+ VITE_FIREBASE_APP_ID=your_app_id
14
+ VITE_FIREBASE_MEASUREMENT_ID=G-XXXXXXXXXX
15
+
16
+ # Firebase OAuth Providers (optional)
17
+ VITE_FACEBOOK_APP_ID=your_facebook_app_id
18
+
19
+ # Encryption — change this to a strong random secret
20
+ VITE_ENCRYPTION_KEY=falak_super_secret_key_change_me_in_production
21
+
22
+ # Groq AI
23
+ VITE_GROQ_API_KEY=your_groq_api_key
24
+ VITE_GROQ_MODEL=llama-3.3-70b-versatile
25
+
26
+ # Paymob
27
+ VITE_PAYMOB_API_KEY=your_paymob_api_key
28
+ VITE_PAYMOB_INTEGRATION_ID=your_integration_id
29
+ VITE_PAYMOB_IFRAME_ID=your_iframe_id
30
+ VITE_PAYMOB_HMAC_SECRET=your_hmac_secret
31
+
32
+ # App
33
+ VITE_APP_NAME=Falak App
34
+ VITE_APP_ENV=development
@@ -0,0 +1,8 @@
1
+ node_modules
2
+ dist
3
+ .env
4
+ .env.local
5
+ .env.production
6
+ *.local
7
+ .DS_Store
8
+ .vscode/settings.json
@@ -0,0 +1,36 @@
1
+ {
2
+ "rules": {
3
+ ".read": false,
4
+ ".write": false,
5
+
6
+ "users": {
7
+ "$uid": {
8
+ ".read": "$uid === auth.uid || root.child('users').child(auth.uid).child('role').val() === 'admin' || root.child('users').child(auth.uid).child('role').val() === 'super_admin'",
9
+ ".write": "$uid === auth.uid || root.child('users').child(auth.uid).child('role').val() === 'super_admin'",
10
+
11
+ "role": {
12
+ ".write": "root.child('users').child(auth.uid).child('role').val() === 'super_admin' || root.child('users').child(auth.uid).child('role').val() === 'admin'"
13
+ }
14
+ }
15
+ },
16
+
17
+ "sessions": {
18
+ "$uid": {
19
+ ".read": "$uid === auth.uid",
20
+ ".write": "$uid === auth.uid"
21
+ }
22
+ },
23
+
24
+ "subscriptions": {
25
+ "$uid": {
26
+ ".read": "$uid === auth.uid || root.child('users').child(auth.uid).child('role').val() === 'admin' || root.child('users').child(auth.uid).child('role').val() === 'super_admin'",
27
+ ".write": "$uid === auth.uid || root.child('users').child(auth.uid).child('role').val() === 'admin' || root.child('users').child(auth.uid).child('role').val() === 'super_admin'"
28
+ }
29
+ },
30
+
31
+ "demo_feed": {
32
+ ".read": "auth !== null",
33
+ ".write": "auth !== null"
34
+ }
35
+ }
36
+ }