Full-stack application for managing and browsing inspirational quotes with admin panel, REST API and mobile application.
- Overview
- Architecture
- Technologies
- Installation
- Quick Start
- Applications
- Documentation
- Available Scripts
Focus is a complete platform for inspirational quotes including:
- ๐ฅ๏ธ Admin Panel - Web interface to manage quotes, topics and users
- ๐ REST API - NestJS backend with JWT authentication and PostgreSQL database (Supabase)
- ๐ฑ Mobile App - React Native/Expo application with infinite scroll and i18n (10 languages)
- โ Complete CRUD for quotes and topics
- โ JWT authentication with roles (admin/user)
- โ Internationalization (FR, EN, ES, AR, DE, IT, ZH, NL, RU, TR with RTL support)
- โ Automatic translation of quotes and topics (DeepL / MyMemory)
- โ Cross-platform icon system (Lucide + Ionicons)
- โ State management with Redux Toolkit + React Query
- โ Modular architecture with BaseEntity (UUIDs)
- โ Infinite scroll and pagination
- โ Light/dark/system theme
- โ Custom visual themes with fonts
- โ Like/Unlike quotes
- โ Filtering by topics
- โ Subscription system (RevenueCat + Stripe)
- โ Manual subscription assignment (Admin)
- โ Promo codes system (Admin + Mobile)
- โ Custom push notifications
- โ iOS/Android widgets
- โ Quote sharing as image
Focus_project/
โโโ apps/
โ โโโ admin/ # Admin panel (Next.js 15)
โ โโโ api/ # REST API (NestJS)
โ โโโ mobile/ # Mobile app (React Native + Expo)
โโโ packages/
โ โโโ eslint-config/ # Shared ESLint configuration
โ โโโ typescript-config/ # Shared TypeScript configuration
โ โโโ ui/ # Shared UI components
โโโ docs/ # Documentation
All entities inherit from BaseEntity:
abstract class BaseEntity {
id: string; // UUID
createdAt: Date; // Auto-generated
updatedAt: Date; // Auto-updated
deletedAt: Date; // Soft delete
}Main entities: Topic, Quote, User, Subscription, SubscriptionPlan, PromoCode
- Redux Toolkit: Global state (auth, theme)
- React Query: Server state with automatic cache
- i18next: Internationalization (FR, EN, ES, AR)
- Next.js 15 (App Router)
- React 19
- TypeScript
- Tailwind CSS v4
- Radix UI (composants accessibles)
- Lucide Icons
- i18n (FR/EN)
- NestJS 10
- TypeORM
- PostgreSQL (Supabase)
- Passport JWT
- bcrypt
- class-validator
- Stripe (paiements web)
- RevenueCat (paiements mobile)
- DeepL / MyMemory (traduction)
- Cloudinary (images)
- React Native
- Expo SDK 54
- TypeScript
- Redux Toolkit
- React Query (TanStack)
- React Navigation
- i18next (10 langues)
- Ionicons
- Expo Notifications
- RevenueCat SDK (abonnements)
- react-native-android-widget / @bacons/apple-targets (widgets)
- Turborepo (monorepo)
- ESLint
- Prettier
- Vercel (dรฉploiement admin)
- EAS Build (builds mobile)
- Node.js >= 18.x
- npm >= 9.x
- Git
# Clone the repository
git clone <repository-url>
cd Focus_project
# Install all dependencies
npm install# From root
npm run dev:api
# Or from apps/api
cd apps/api
npm run start:devAPI will be available at http://localhost:3001
cd apps/api
# Reset DB (optional)
./reset-database.sh
# Seed topics
node seed-topics.js# From root
npm run dev:admin
# Or from apps/admin
cd apps/admin
npm run devPanel will be available at http://localhost:3000
Default admin account:
- Email:
admin@focus.com - Password:
admin123
# From root
npm run dev:mobile
# Or from apps/mobile
cd apps/mobile
npm startScan the QR code with Expo Go or press:
ifor iOS Simulatorafor Android Emulatorwfor Web
Web interface to manage content.
Features:
- Dashboard with statistics (users, revenue, subscriptions)
- CRUD Topics (name, title, description, icon, color, premium)
- CRUD Quotes (text, author, topic)
- User and subscription management
- Manual subscription assignment (with password verification)
- Promo codes management (creation, list, details, users)
- Visual themes and fonts management
- Subscription plans management
- Payment history (Stripe + RevenueCat)
- Image upload (Cloudinary)
- JWT authentication
- i18n (FR/EN)
URL: http://localhost:3000
NestJS backend with modular architecture.
Main endpoints:
POST /auth/login- AuthenticationPOST /auth/register- RegistrationGET /quotes- List quotes (pagination)GET /quotes/:id- Quote by IDPOST /quotes/:id/like- Like a quoteGET /topics- List topicsGET /topics/:id- Topic by IDPOST /subscriptions/checkout- Create Stripe sessionPOST /subscriptions/webhook/revenuecat- RevenueCat webhookPOST /subscriptions/sync-revenuecat- Sync entitlementsPOST /subscriptions/apply-promo-code- Apply promo codePOST /subscriptions/users/:userId/assign-subscription- Manual assignment (admin)GET /subscriptions/plans- List plansPOST /subscriptions/promo-codes- Create promo code (admin)GET /subscriptions/promo-codes- List promo codes (admin)POST /translations/translate- Translate text
URL: http://localhost:3001
Documentation: See apps/api/README.md
React Native application with Expo.
Features:
- Infinite scroll quotes
- Pull-to-refresh
- Like/Unlike and favorites
- Filter by topics
- Authentication
- User profile with statistics
- Settings (language, theme, mode)
- Automatic translation of quotes and topics
- Custom visual themes with fonts
- Push notifications configurable (hours, days)
- Widgets iOS and Android
- Share quotes as image
- Premium subscription via RevenueCat (iOS/Android)
- Promo codes for free premium access
- Automatic subscription synchronization
- i18n (FR, EN, ES, AR, DE, IT, ZH, NL, RU, TR)
Technologies:
- Redux Toolkit (state management)
- React Query (server state)
- RevenueCat SDK (subscriptions)
- React Navigation (navigation)
- i18next (internationalization)
- Expo Notifications (push)
- Expo Sharing (sharing)
- ARCHITECTURE_IMPROVEMENTS.md - Architecture improvements (BaseEntity, Redux, React Query)
- ICONS_SYSTEM.md - Cross-platform icon system
- TESTING_GUIDE.md - Testing guide
- apps/mobile/MIGRATION_GUIDE.md - Migration Context โ Redux + React Query
- apps/mobile/I18N_IMPLEMENTATION.md - i18n implementation
- apps/api/MIGRATION_UUID.md - Migration to UUIDs
If you encounter Invalid admin password error during manual subscription assignment:
Cause: The provided password doesn't match the bcrypt hash stored in database.
Solutions:
-
Test admin dashboard login:
- URL:
http://localhost:3000/login - Credentials:
admin@focus.com/admin123 - If login fails โ Reset password
- URL:
-
Reset via seed script:
cd apps/api npm run db:seed:adminNew credentials:
admin@focus.com/admin123 -
Reset via SQL:
# Generate bcrypt hash node -e "const bcrypt = require('bcrypt'); bcrypt.hash('YourPassword', 10, (err, hash) => console.log(hash));" # Update in database (Supabase SQL Editor) UPDATE "user" SET password = 'GENERATED_HASH_ABOVE' WHERE email = 'admin@focus.com' AND "isAdmin" = true;
Note: Manual subscription assignment requires admin password to secure this sensitive action.
To avoid API cold starts (free hosting), the system implements automatic polling:
- Mobile: Ping
/healthevery 60 seconds - Admin: Ping
/health/statsevery 60 seconds + auto-refresh dashboard
Configuration: Services configured in apps/mobile/App.tsx and apps/admin/src/app/dashboard/page.tsx
Mobile app automatically checks subscription expiration:
- Interval: Every 5 minutes in background
- On foreground: Immediate check when app returns
- Action: Automatically switches to "free tier" if subscription expired
File: apps/mobile/src/services/subscriptionSyncService.ts
If users report a "white screen" during loading:
Cause: Skeletons have too low opacity (8%) and are barely visible.
Solution: Skeletons have been improved with:
- Opacity increased to 15% (+87% visibility)
- More pronounced pulse animation (50-90% instead of 30-70%)
- Shadows added for depth
- Increased heights and spacing
File: apps/mobile/src/components/LoadingSkeleton.tsx
Standard to follow:
โ Keep:
- Public API documentation (JSDoc)
- Complex logic explanation
- Security notes and important TODOs
- Technical references (links to docs)
โ Remove:
- Obvious comments (
// Get user) - Redundant comments (function name = comment)
- Commented code (dead code)
- Useless separators (
// ========)
Method: Clean progressively when modifying existing files. Don't automate to avoid bugs.
# Development
npm run dev # Start all apps
npm run dev:admin # Start admin only
npm run dev:api # Start API only
npm run dev:mobile # Start mobile only
# Build
npm run build # Build all apps
npm run build:admin # Build admin
npm run build:api # Build API
# Linting
npm run lint # Lint all appsnpm run start:dev # Development mode (watch)
npm run start:prod # Production mode
npm run build # Compile TypeScript
npm test # Unit tests
npm run test:e2e # E2E testsnpm run dev # Development mode
npm run build # Production build
npm run start # Start in production
npm run lint # Lint codenpm start # Start Expo
npm run android # Open on Android
npm run ios # Open on iOS
npm run web # Open on Web- ๐ซ๐ท Franรงais (fr) - Source language
- ๐ฌ๐ง English (en)
- ๐ช๐ธ Espaรฑol (es)
- ๐ธ๐ฆ ุงูุนุฑุจูุฉ (ar) - with RTL support
- ๐ฉ๐ช Deutsch (de)
- ๐ฎ๐น Italiano (it)
- ๐จ๐ณ ไธญๆ (zh)
- ๐ณ๐ฑ Nederlands (nl)
- ๐ท๐บ ะ ัััะบะธะน (ru)
- ๐น๐ท Tรผrkรงe (tr)
The app has an automatic translation feature for quotes and topics:
- Enable in Settings โ Automatic translation
- Uses DeepL API (primary) and MyMemory (fallback)
- Local cache to avoid repeated API calls
- Automatically translates from French to selected language
Mobile: Settings โ Language โ Select language Admin: Language selector in header
Mobile app supports 3 modes:
- โ๏ธ Light - Light theme
- ๐ Dark - Dark theme
- ๐ System - Follow system theme
The app offers custom visual themes:
- Wallpapers with images
- Custom fonts per theme
- Manageable from admin panel
Admin:
- Email:
admin@focus.com - Password:
admin123
User:
- Email:
user@focus.com - Password:
user123
JWT tokens are stored in:
- Admin:
localStorage - Mobile:
AsyncStorage
Validity duration: 7 days
The app integrates a premium subscription system via RevenueCat (mobile) and Stripe (web):
- Monthly and annual plans configurable from admin
- Free trial period (freemium)
- Promo codes for temporary premium access
- Access to premium topics
- Custom push notifications
- Exclusive visual themes
- Unlimited automatic translation
Administrators can:
- Manually assign a subscription to a user
- Requires admin password confirmation
- Visible in admin interface under each user profile
Admin:
- Create promo codes with custom duration (e.g., 7, 30, 90 days)
- View list of users who used each code
- Track usage count
Mobile User:
- Enter promo code during registration
- Automatic premium application for defined duration
- One promo code per account
Required environment variables:
# Stripe (web payments)
STRIPE_SECRET_KEY=sk_...
STRIPE_WEBHOOK_SECRET=whsec_...
# RevenueCat (mobile payments)
REVENUECAT_API_KEY=...
REVENUECAT_WEBHOOK_SECRET=...See docs/SUBSCRIPTIONS_SETUP.md for more details.
- Fork the project
- Create a branch (
git checkout -b feature/AmazingFeature) - Commit changes (
git commit -m 'Add AmazingFeature') - Push to branch (
git push origin feature/AmazingFeature) - Open a Pull Request
This project is licensed under MIT.
- Cรฉdric Karungu - Lead Developer
- NestJS - Backend framework
- Next.js - React framework
- Expo - React Native platform
- Radix UI - Accessible components
- Turborepo - Monorepo tool
- Stripe - Web payments
- RevenueCat - Mobile payments
- DeepL - Automatic translation
- Supabase - PostgreSQL database
- Cloudinary - Image management