A modern Next.js 16 dashboard application with Clerk authentication and PostgreSQL database integration for managing agencies and contacts with daily usage limits.
π Application Live: https://agency-hub01.vercel.app
Create your own account using the sign-up page, or use these test credentials:
- Email:
demo@agencyhub.com - Password:
Demo@2024
Note: If test credentials don't work, please create a new account via the sign-up page.
- π User Authentication - Secure authentication with Clerk (required to access dashboard)
- π’ View All Agencies - Access complete database of agencies in a dedicated table page
- π₯ View Contacts - Browse contacts database with pagination in a separate table page
- π― Daily Limit System - Users limited to 50 contact views per day
- π³ Upgrade Prompt - Modal appears when daily limit is exceeded (no payment integration)
- π Usage Tracking - Monitor daily contact views with PostgreSQL database
- π Dark Mode - Theme toggle with system preference detection
- π± Responsive Design - Optimized for all screen sizes
- π Search & Filter - Advanced search across agencies and contacts
- π Usage Analytics - Visual charts showing your daily usage patterns
| Category | Technology |
|---|---|
| Framework | Next.js 16 (App Router) |
| Authentication | Clerk |
| Database | PostgreSQL (Neon) |
| Styling | Tailwind CSS v4 + shadcn/ui |
| Deployment | Vercel |
| Language | TypeScript |
| Version Control | GitHub |
| Requirement | Status | Implementation |
|---|---|---|
| User authentication required | β | Clerk authentication with middleware protection |
| View all agencies | β | /dashboard/agencies page with full database table |
| 50 contacts/day limit | β | PostgreSQL tracking with daily reset |
| Upgrade prompt on limit | β | Modal with blur effect (no payment) |
| Separate table pages | β | /agencies and /contacts routes |
| Next.js 16 | β | Using App Router and React 19 |
| Clerk authentication | β | Full integration with protected routes |
| Vercel deployment | β | Optimized for Vercel platform |
| GitHub repository | β | Version controlled with Git |
| System design diagram | β | See diagram section below |
- Node.js 18+ installed
- Clerk account (free tier available)
- Neon database or any PostgreSQL provider
- Git for version control
-
Clone the repository:
git clone https://github.com/BEN-OSSAMA/AgencyHub.git cd AgencyHub -
Install dependencies:
npm install
-
Configure environment variables:
Create
.env.localin the root directory:# Clerk Authentication Keys NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_your_key_here CLERK_SECRET_KEY=sk_test_your_secret_key_here NEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in NEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up # PostgreSQL Database Connection DATABASE_URL=postgresql://user:password@host:5432/database?sslmode=require
-
Set up the database:
Run the SQL initialization script:
# Using psql psql -d your_database -f scripts/001-create-tables.sql # Or use Neon SQL Editor to run the script
-
Start development server:
npm run dev
-
Access the application:
Open http://localhost:3000 in your browser
-
Push code to GitHub:
git init git add . git commit -m "Initial commit" git branch -M main git remote add origin https://github.com/BEN-OSSAMA/AgencyHub.git git push -u origin main
-
Import to Vercel:
- Visit vercel.com and sign in
- Click "Add New Project"
- Import your GitHub repository
- Vercel will auto-detect Next.js configuration
-
Configure Environment Variables:
β οΈ CRITICAL: Set these in Vercel Project Settings β Environment VariablesVariable Value Required NEXT_PUBLIC_CLERK_PUBLISHABLE_KEYFrom Clerk Dashboard β Yes CLERK_SECRET_KEYFrom Clerk Dashboard β Yes NEXT_PUBLIC_CLERK_SIGN_IN_URL/sign-inβ Yes NEXT_PUBLIC_CLERK_SIGN_UP_URL/sign-upβ Yes DATABASE_URLYour PostgreSQL connection string β Yes Enable for: Production, Preview, and Development
-
Deploy:
- Click "Deploy"
- Wait for build to complete (~2-3 minutes)
- Your app will be live at
your-app.vercel.app
-
Update Clerk Settings:
- Add your Vercel domain to Clerk Dashboard β Settings β Domains
- Update allowed origins to include your production URL
flowchart TD
Start([User Opens App]) --> Auth{Authenticated?}
Auth -->|No| SignIn[Sign In Page]
Auth -->|Yes| Dashboard[Dashboard Home]
SignIn --> Clerk[Clerk Authentication]
Clerk --> Dashboard
Dashboard --> NavChoice{User Navigation}
NavChoice --> Agencies[Agencies Page]
NavChoice --> Contacts[Contacts Page]
Agencies --> AgenciesAPI[/api/agencies]
AgenciesAPI --> AgenciesJSON[(agencies.json)]
AgenciesJSON --> AgenciesTable[Display All Agencies Table]
Contacts --> CheckLimit{Check Daily Limit}
CheckLimit --> GetUsage[/api/usage GET]
GetUsage --> DB[(PostgreSQL Database)]
DB --> UsageData[user_daily_usage table]
UsageData --> LimitCheck{Views < 50?}
LimitCheck -->|Yes| ContactsAPI[/api/contacts]
LimitCheck -->|No| UpgradeModal[Upgrade Modal + Blur]
ContactsAPI --> ContactsJSON[(contacts.json)]
ContactsJSON --> ContactsTable[Display Contacts Table]
ContactsTable --> IncrementUsage[/api/usage POST]
IncrementUsage --> DB
UpgradeModal --> End([User Sees Upgrade Prompt])
AgenciesTable --> End
ContactsTable --> End
style Start fill:#4ade80
style End fill:#f87171
style Dashboard fill:#60a5fa
style Clerk fill:#fbbf24
style DB fill:#a78bfa
style UpgradeModal fill:#fb923c
- Authentication Layer: Users must authenticate via Clerk before accessing any dashboard features
- Dashboard Router: After authentication, users can navigate to Agencies or Contacts pages
- Agencies Flow: Direct access to view all agencies in table format (no limits)
- Contacts Flow:
- System checks daily usage from PostgreSQL
- If under 50 views: display contacts and increment counter
- If 50+ views: show upgrade modal with blurred content
- Database: PostgreSQL stores daily usage per user with automatic date tracking
AgencyHub/
βββ app/
β βββ api/ # API Routes
β β βββ agencies/
β β β βββ route.ts # GET all agencies
β β βββ contacts/
β β β βββ route.ts # GET paginated contacts
β β βββ usage/
β β βββ route.ts # GET/POST usage tracking
β βββ dashboard/ # Protected dashboard pages
β β βββ agencies/
β β β βββ page.tsx # All agencies table
β β βββ contacts/
β β β βββ page.tsx # Contacts table with limit
β β βββ layout.tsx # Dashboard layout
β β βββ page.tsx # Dashboard home
β βββ sign-in/[[...sign-in]]/
β β βββ page.tsx # Clerk sign-in
β βββ sign-up/[[...sign-up]]/
β β βββ page.tsx # Clerk sign-up
β βββ layout.tsx # Root layout
β βββ page.tsx # Landing page
βββ components/
β βββ agencies/
β β βββ agencies-table.tsx # Agencies table component
β βββ contacts/
β β βββ contacts-table.tsx # Contacts table component
β β βββ limit-reached-modal.tsx # Limit exceeded modal
β β βββ usage-banner.tsx # Usage indicator banner
β βββ dashboard/
β β βββ usage-chart.tsx # Usage analytics chart
β βββ ui/ # shadcn/ui components
βββ data/
β βββ agencies.json # Static agencies data
β βββ contacts.json # Static contacts data
βββ lib/
β βββ db.ts # PostgreSQL connection
β βββ types.ts # TypeScript interfaces
β βββ usage.ts # Usage tracking logic
β βββ utils.ts # Utility functions
βββ scripts/
β βββ 001-create-tables.sql # Database schema
βββ middleware.ts # Clerk auth middleware
βββ package.json
| Endpoint | Method | Description | Auth | Purpose |
|---|---|---|---|---|
/api/agencies |
GET | Retrieve all agencies | No | Agencies page data |
/api/contacts |
GET | Get paginated contacts | Yes | Contacts page data |
/api/usage |
GET | Get user's daily usage | Yes | Check limit status |
/api/usage |
POST | Increment contact views | Yes | Track usage |
// middleware.ts
import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server'
const isPublicRoute = createRouteMatcher(['/', '/sign-in(.*)', '/sign-up(.*)'])
export default clerkMiddleware(async (auth, req) => {
if (!isPublicRoute(req)) {
await auth.protect()
}
})All /dashboard/* routes require authentication via Clerk.
Database Schema:
CREATE TABLE user_daily_usage (
id SERIAL PRIMARY KEY,
user_id VARCHAR(255) NOT NULL,
usage_date DATE NOT NULL DEFAULT CURRENT_DATE,
contacts_viewed INTEGER DEFAULT 0,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW(),
UNIQUE(user_id, usage_date)
);Logic Flow:
- User visits contacts page
- System queries
user_daily_usagefor today's count - If count < 50: display contacts and increment
- If count β₯ 50: show upgrade modal with blurred table
When limit is reached:
- Modal overlay appears
- Contact table becomes blurred
- "Upgrade Now" button (UI only, no payment)
- User cannot interact with contacts until next day
The dashboard includes a visual usage chart that displays:
- Today's usage progress (with progress bar)
- Weekly total views
- Remaining views for the day
- Visual indicators when approaching or reaching the limit
The chart provides real-time feedback on your daily contact viewing activity, helping you manage your usage effectively.
- Navigate to
/dashboardwithout logging in - Should redirect to
/sign-in - After authentication, should access dashboard
- Log in to dashboard
- Navigate to "Agencies" page
- Should see complete table of all agencies
- No limits applied
- Log in to dashboard
- Navigate to "Contacts" page
- View contacts repeatedly (each page view counts)
- After 50 views, upgrade modal should appear
- Table should be blurred and non-interactive
- Next day (or manual DB reset), limit resets
- Verify
DATABASE_URLis set correctly - Check database credentials
- Ensure database is accessible from your IP
- For Neon, check connection pooling settings
- Verify keys match your Clerk instance
- Check allowed origins in Clerk dashboard
- Ensure URLs are correctly configured
- Clear browser cache and cookies
- Run
npm installto ensure dependencies are installed - Check Node.js version (should be 18+)
- Clear
.nextfolder and rebuild - Ensure all environment variables are set
Oussama Ben Kacem
- GitHub: @BEN-OSSAMA
- LinkedIn: Oussama Ben Kacem
- Live Demo: https://agency-hub01.vercel.app
- Next.js - The React Framework for Production
- Clerk - User Authentication & Management
- shadcn/ui - Beautifully Designed Components
- Tailwind CSS - Utility-First CSS Framework
- Neon - Serverless PostgreSQL Database
- Vercel - Deployment Platform
β If you found this project helpful, please give it a star on GitHub!
π Live Application: https://agency-hub01.vercel.app
