Skip to content

Commit a132bde

Browse files
committed
feat: Complete Q&A Platform implementation with RBAC
✨ Core Features: - Complete Q&A system with admin dashboard - Role-based access control via Clerk - API routes for question management - Search functionality for users - Custom middleware for auth protection 🏗️ Architecture: - Organized component structure with Header, QuestionForm, QuestionItem, QuestionList - Separate admin and API routes - Database integration with Prisma & Drizzle - Type-safe implementation with globals.d.ts - Middleware for request handling 🔧 Technical Structure: - Modular component architecture in /components - API handlers in /api - Admin dashboard in /admin - Search implementation in /searchUsers - Custom middleware for auth flow - Global types and utilities Production-ready implementation with complete error handling and type safety.
1 parent e5169d2 commit a132bde

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+10284
-6
lines changed

Diff for: .gitignore

+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
# Dependencies
2+
/node_modules
3+
/.pnp
4+
.pnp.js
5+
.yarn/install-state.gz
6+
7+
# Testing
8+
/coverage
9+
10+
# Next.js
11+
/.next/
12+
/out/
13+
next-env.d.ts
14+
15+
# Production
16+
/build
17+
18+
# Misc
19+
.DS_Store
20+
*.pem
21+
22+
# Debug
23+
npm-debug.log*
24+
yarn-debug.log*
25+
yarn-error.log*
26+
27+
# Local env files
28+
.env*.local
29+
.env
30+
.env.development
31+
.env.test
32+
.env.production
33+
34+
# Vercel
35+
.vercel
36+
37+
# TypeScript
38+
*.tsbuildinfo
39+
40+
# IDE - VSCode
41+
.vscode/*
42+
!.vscode/settings.json
43+
!.vscode/tasks.json
44+
!.vscode/launch.json
45+
!.vscode/extensions.json
46+
47+
# IDE - IntelliJ/WebStorm
48+
.idea/
49+
*.iml
50+
*.iws
51+
*.ipr
52+
.idea_modules/
53+
54+
# Prisma
55+
/prisma/*.db
56+
/prisma/migrations/
57+
58+
# Database
59+
*.sqlite
60+
*.sqlite3
61+
62+
# Logs
63+
logs
64+
*.log
65+
66+
# OS generated files
67+
.DS_Store
68+
.DS_Store?
69+
._*
70+
.Spotlight-V100
71+
.Trashes
72+
ehthumbs.db
73+
Thumbs.db
74+
75+
# Drizzle
76+
drizzle.config.*
77+
.drizzle/
78+
79+
# Optional npm cache directory
80+
.npm
81+
82+
# Optional eslint cache
83+
.eslintcache
84+
85+
# Cache directories
86+
.cache/
87+
.temp/

Diff for: README.md

+34-6
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,35 @@
1-
# clerk-qa-platform
2-
A modern Q&A platform built with Next.js, featuring role-based access control (RBAC) using Clerk. This full-stack app demonstrates enterprise-level authentication, authorization patterns, and responsive UI design.
31

4-
![Next.js](https://img.shields.io/badge/Next.js-15-black)
5-
![TypeScript](https://img.shields.io/badge/TypeScript-5-blue)
6-
![TailwindCSS](https://img.shields.io/badge/TailwindCSS-3-06B6D4)
7-
![Clerk](https://img.shields.io/badge/Clerk-Auth-purple)
2+
3+
## Getting Started
4+
5+
1. Clone the repository:
6+
7+
```bash
8+
git clone https://github.com/tyaga001/clerk-qa-platform
9+
```
10+
11+
2. Install the dependencies
12+
13+
```bash
14+
npm install
15+
```
16+
17+
3. Set up a Clerk application and Neon database. Then create a Create a .env.local file in the root directory of the project and add the following keys
18+
19+
```bash
20+
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=
21+
CLERK_SECRET_KEY=
22+
NEON_DATABASE_URL=
23+
```
24+
25+
4. Initialize the database
26+
27+
```bash
28+
npx drizzle-kit push
29+
```
30+
31+
5. Start the Next.js development server
32+
33+
```bash
34+
npm run dev
35+
```

Diff for: components.json

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"$schema": "https://ui.shadcn.com/schema.json",
3+
"style": "new-york",
4+
"rsc": true,
5+
"tsx": true,
6+
"tailwind": {
7+
"config": "tailwind.config.ts",
8+
"css": "src/app/globals.css",
9+
"baseColor": "neutral",
10+
"cssVariables": false,
11+
"prefix": ""
12+
},
13+
"aliases": {
14+
"components": "@/components",
15+
"utils": "@/lib/utils",
16+
"ui": "@/components/ui",
17+
"lib": "@/lib",
18+
"hooks": "@/hooks"
19+
},
20+
"iconLibrary": "lucide"
21+
}

Diff for: drizzle/0000_colorful_fallen_one.sql

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
CREATE TABLE "answers" (
2+
"id" serial PRIMARY KEY NOT NULL,
3+
"text" text NOT NULL,
4+
"approved" boolean,
5+
"user_id" integer NOT NULL,
6+
"question_id" integer NOT NULL,
7+
"timestamp" timestamp with time zone DEFAULT now()
8+
);
9+
--> statement-breakpoint
10+
CREATE TABLE "questions" (
11+
"id" serial PRIMARY KEY NOT NULL,
12+
"text" text NOT NULL,
13+
"approved" boolean,
14+
"user_id" integer NOT NULL,
15+
"timestamp" timestamp with time zone DEFAULT now()
16+
);
17+
--> statement-breakpoint
18+
ALTER TABLE "answers" ADD CONSTRAINT "answers_question_id_questions_id_fk" FOREIGN KEY ("question_id") REFERENCES "public"."questions"("id") ON DELETE no action ON UPDATE no action;

Diff for: drizzle/0001_fair_edwin_jarvis.sql

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
ALTER TABLE "answers" RENAME COLUMN "user_id" TO "contributor_id";--> statement-breakpoint
2+
ALTER TABLE "questions" RENAME COLUMN "user_id" TO "contributor_id";--> statement-breakpoint
3+
ALTER TABLE "answers" ADD COLUMN "contributor" text NOT NULL;--> statement-breakpoint
4+
ALTER TABLE "questions" ADD COLUMN "contributor" text NOT NULL;

Diff for: drizzle/0002_previous_manta.sql

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
ALTER TABLE "answers" RENAME COLUMN "text" TO "ans";--> statement-breakpoint
2+
ALTER TABLE "questions" RENAME COLUMN "text" TO "quiz";

Diff for: drizzle/meta/0000_snapshot.json

+127
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
{
2+
"id": "47a46543-bae2-400b-abbc-36e04040ba86",
3+
"prevId": "00000000-0000-0000-0000-000000000000",
4+
"version": "7",
5+
"dialect": "postgresql",
6+
"tables": {
7+
"public.answers": {
8+
"name": "answers",
9+
"schema": "",
10+
"columns": {
11+
"id": {
12+
"name": "id",
13+
"type": "serial",
14+
"primaryKey": true,
15+
"notNull": true
16+
},
17+
"text": {
18+
"name": "text",
19+
"type": "text",
20+
"primaryKey": false,
21+
"notNull": true
22+
},
23+
"approved": {
24+
"name": "approved",
25+
"type": "boolean",
26+
"primaryKey": false,
27+
"notNull": false
28+
},
29+
"user_id": {
30+
"name": "user_id",
31+
"type": "integer",
32+
"primaryKey": false,
33+
"notNull": true
34+
},
35+
"question_id": {
36+
"name": "question_id",
37+
"type": "integer",
38+
"primaryKey": false,
39+
"notNull": true
40+
},
41+
"timestamp": {
42+
"name": "timestamp",
43+
"type": "timestamp with time zone",
44+
"primaryKey": false,
45+
"notNull": false,
46+
"default": "now()"
47+
}
48+
},
49+
"indexes": {},
50+
"foreignKeys": {
51+
"answers_question_id_questions_id_fk": {
52+
"name": "answers_question_id_questions_id_fk",
53+
"tableFrom": "answers",
54+
"tableTo": "questions",
55+
"columnsFrom": [
56+
"question_id"
57+
],
58+
"columnsTo": [
59+
"id"
60+
],
61+
"onDelete": "no action",
62+
"onUpdate": "no action"
63+
}
64+
},
65+
"compositePrimaryKeys": {},
66+
"uniqueConstraints": {},
67+
"policies": {},
68+
"checkConstraints": {},
69+
"isRLSEnabled": false
70+
},
71+
"public.questions": {
72+
"name": "questions",
73+
"schema": "",
74+
"columns": {
75+
"id": {
76+
"name": "id",
77+
"type": "serial",
78+
"primaryKey": true,
79+
"notNull": true
80+
},
81+
"text": {
82+
"name": "text",
83+
"type": "text",
84+
"primaryKey": false,
85+
"notNull": true
86+
},
87+
"approved": {
88+
"name": "approved",
89+
"type": "boolean",
90+
"primaryKey": false,
91+
"notNull": false
92+
},
93+
"user_id": {
94+
"name": "user_id",
95+
"type": "integer",
96+
"primaryKey": false,
97+
"notNull": true
98+
},
99+
"timestamp": {
100+
"name": "timestamp",
101+
"type": "timestamp with time zone",
102+
"primaryKey": false,
103+
"notNull": false,
104+
"default": "now()"
105+
}
106+
},
107+
"indexes": {},
108+
"foreignKeys": {},
109+
"compositePrimaryKeys": {},
110+
"uniqueConstraints": {},
111+
"policies": {},
112+
"checkConstraints": {},
113+
"isRLSEnabled": false
114+
}
115+
},
116+
"enums": {},
117+
"schemas": {},
118+
"sequences": {},
119+
"roles": {},
120+
"policies": {},
121+
"views": {},
122+
"_meta": {
123+
"columns": {},
124+
"schemas": {},
125+
"tables": {}
126+
}
127+
}

0 commit comments

Comments
 (0)