A Google Forms replica built specifically for college instructors and students. Create, distribute, and analyze forms with advanced features like form templates, role-based access, deadline management, and comprehensive response analytics.
- Create Custom Forms β Build surveys, quizzes, feedback forms, and questionnaires
- Multiple Question Types β Text, textarea, number, email, date, and multiple-choice (MCQ)
- Form Templates β Quick-start with 7 pre-built templates:
- Event Registration
- Course Evaluation
- Faculty Feedback Form
- Quiz / Internal Test
- Leave Application
- Lab Feedback
- Doubt/Query Submission
- Access Control β Public forms or department-specific group forms
- Deadline Management β Set response deadlines and auto-close expired forms
- Response Management β View, filter, and download responses in real-time
- Report Release β Control when students can see form results
- Theme Customization β Choose theme colors for forms
- Response Restrictions β Allow single or multiple responses per student
- Easy Form Access β Access forms via unique form codes
- Fill & Submit β Intuitive interface for completing forms
- Multi-question Support β Answer various question types seamlessly
- Submission Confirmation β Get confirmation after submission
- View Results β See form results when instructor releases reports
- Oracle Database β Enterprise-grade SQL backend
- Advanced Triggers & Procedures β PL/SQL automation for deadline validation and response tracking
- Audit Logging β Track form creation and response submissions
- JSON Templates β Efficient template storage using CLOB
| Component | Technology |
|---|---|
| Backend | Node.js with Express.js (ES6 modules) |
| Frontend | HTML5, CSS3, Vanilla JavaScript, Tailwind CSS |
| Database | Oracle SQL (XEPDB1) with PL/SQL |
| Server | Express.js (v5.2.1) |
| Auth | JWT (jsonwebtoken) + bcryptjs |
| ORM/Driver | oracledb (v6.10.0) |
- Node.js v16+ (uses
--env-fileflag) - npm v8+
- Oracle Database (XE, Enterprise, or compatible)
- Git
git clone https://github.com/sagnik0606-ux/formflow.git
cd formflownpm installCreate/Update .env file:
DB_USER=user
DB_PASSWORD=user_pwd
DB_HOST=localhost
DB_PORT=1521
DB_SERVICE=XEPDB1
NODE_ENV=development
PORT=8000
JWT_SECRET=your_strong_random_secret_here
β οΈ Important: Never commit.envto Git. It's already in.gitignore. TheJWT_SECRETmust be a long, random string β it signs all authentication tokens.
Run the SQL setup script in your Oracle Database (SQL Developer or SQL*Plus):
# Via SQL Developer, run project_db.sql entirely
# OR via sqlplus:
sqlplus user/user@XEPDB1 @project_db.sqlThis creates:
- 8 tables (users, forms, questions, options, responses, answers, audit_logs, form_templates)
- 4 PL/SQL triggers (deadline validation, response blocking, audit tracking)
- 2 PL/SQL procedures (form status toggle, expire forms)
- 1 PL/SQL function (count responses)
- 7 pre-loaded form templates (JSON-based)
- Sample data (2 users, 2 forms, questions, responses)
If you have existing users with plain-text passwords in the database, run the one-time migration script to hash them without resetting accounts:
node --env-file=.env migrate_passwords.jsDevelopment (with auto-reload):
npm run devProduction:
npm startServer runs at http://localhost:8000
formflow/
βββ public/
β βββ signin.html # Login page (glass-morphism UI)
β βββ dashboard.html # Main instructor dashboard
β βββ auth-helper.js # Client-side JWT storage & auth header utility
β βββ newForm.js # Create/edit forms + template selection
β βββ myForms.js # Instructor's form list + management
β βββ fillForm.js # Student form-filling interface
β βββ myResponses.html # Student view their responses
β βββ audit.js # Audit log viewer
βββ routes/
β βββ auth.js # Login/signup/me/change-password endpoints
β βββ forms.js # Form CRUD + template endpoints (JWT-protected)
β βββ responses.js # Response submission + retrieval (JWT-protected)
βββ middleware/
β βββ auth.js # requireAuth JWT verification middleware
βββ db.js # Oracle connection manager
βββ server.js # Express app entry point
βββ package.json # Dependencies + scripts
βββ project_db.sql # Full database schema + data
βββ migrate_passwords.js # One-time password hashing migration script
βββ tmp_db_update.js # Migration script (run once)
βββ .env # Database credentials + JWT secret (NEVER commit)
βββ .gitignore # Git ignore rules
βββ README.md # This file
-
POST /auth/loginβ User login- Body:
{ email, password } - Response:
{ ok: true, token: "<jwt>", redirect: "/dashboard.html" }
- Body:
-
POST /auth/signupβ User registration- Body:
{ name, email, password, user_type (student|faculty), department, batch? }
- Body:
-
GET /auth/meβ Get current user info (requires JWT) -
POST /auth/change-passwordβ Change own password (requires JWT)- Body:
{ current_password, new_password }
- Body:
All protected endpoints require the header:
Authorization: Bearer <token>
-
POST /forms/createβ Create new form- Body:
{ title, description, access_type, target_dept?, deadline, theme_color? } - Response:
{ form_id, form_code }
- Body:
-
GET /forms/allβ Get all user's forms- Returns: Form list with response counts
-
GET /forms/:formIdβ Get form details + questions- Returns: Form + questions + options
-
PUT /forms/:formIdβ Update form details -
DELETE /forms/:formIdβ Delete form -
GET /forms/by-code/:codeβ Get form by unique code (student access) -
GET /forms/templatesβ Get all form templates -
POST /forms/from-templateβ Create form from template
-
POST /responses/submitβ Submit form response- Body:
{ form_id, answers: [{ question_id, answer_text|answer_number|option_id }] }
- Body:
-
GET /responses/form/:formIdβ Get all responses to a form (instructor only)- Returns: Aggregate stats + individual responses
-
GET /responses/user/:userIdβ Get responses submitted by user (student view)
| Table | Purpose |
|---|---|
users |
Faculty & student accounts |
forms |
Form definitions + metadata |
questions |
Form questions with types |
options |
MCQ options |
responses |
Form submissions (one per student per form) |
answers |
Individual answers to questions |
form_templates |
JSON-based form templates |
audit_logs |
Action tracking (create, submit, etc.) |
- Forms cannot have past deadlines (trigger:
trg_form_deadline_check) - Responses blocked on expired/closed forms (trigger:
trg_prevent_invalid_response) - Auto-populate response counts via function:
fn_get_response_count()
- Modern frosted glass design using Tailwind CSS
- DM Sans font family
- Toast notifications (error/success)
- Responsive mobile-first layout
- Email + password authentication
- Sign-up toggle for new users
- Remember-me option (optional)
- Overview: Total forms, responses pending, active forms
- Create new form or from template
- Manage existing forms (edit, delete, view responses)
- Analytics sidebar
- Drag-and-drop question reordering
- Add/remove questions dynamically
- Rich question customization (required field, help text)
- Template quick-start
- Live preview
- Progressive form rendering
- Type-specific input validation
- Progress indicator
- Submit confirmation
- Password Hashing β Passwords are hashed with
bcryptjs(cost factor 12) on signup and verified withbcrypt.compare()on login. Plain-text passwords are never stored. - JWT Authentication β A signed JWT (
userId+userType, 8h expiry) is issued on login and must be sent as a Bearer token on all protected requests. - Auth Middleware β
middleware/auth.jsverifies the JWT and injectsreq.useron every protected route. The client never supplies auser_iddirectly. - IDOR Protection β All routes in
forms.jsandresponses.jsderive ownership from the verified JWT (req.user.id), not from any client-supplied parameter. - Database Credentials β Stored in
.env, never hardcoded..envis gitignored. - Input Validation β All Oracle queries use bind parameters to prevent SQL injection.
- Audit Logs β Track all create/submit actions.
- Password Migration β
migrate_passwords.jsavailable to hash any legacy plain-text passwords without resetting accounts.
- Security Headers β
helmetnot yet added; headers likeContent-Security-PolicyandX-Frame-Optionsare missing. - Rate Limiting β
express-rate-limitnot yet added; login/signup endpoints are still vulnerable to brute-force. - HttpOnly Cookies β Token is currently stored client-side in JS; switching to HttpOnly cookies would protect against XSS token theft.
- CORS β Enabled globally with no origin restriction; should be locked to known origins in production.
npm run dev
# Auto-reloads on file changesnpm startAfter running project_db.sql:
- Faculty Account: email alice.miller@college.edu (password: hashedpw123)
- Student Account: email Dr. Bob Smith (password: hashedpw456)
- Sample Forms: "Midsem Feedback" (Form ID: 1), "CS Dept Survey" (Form ID: 2)
# Check Oracle is running
sqlplus /nolog
SQL> connect user/user@XEPDB1
# Check .env credentials match
cat .env# Reinstall dependencies
rm -rf node_modules package-lock.json
npm install# Change in .env: PORT=8001
# Or kill the process:
lsof -i :8000
kill -9 <PID>- Check deadline hasn't passed (DB trigger will reject)
- Verify all required questions are answered
- Check
audit_logstable for errors
- JWT expires after 8 hours β log in again for a fresh token
- Ensure
JWT_SECRETin.envis set and hasn't changed between server restarts
- Bcrypt password hashing
- JWT authentication
- JWT refresh tokens
-
helmetsecurity headers - Rate limiting on auth endpoints (
express-rate-limit) - HttpOnly Cookie token storage
- Conditional branching (skip logic)
- Email notifications on new responses
- Advanced analytics charts (Chart.js/D3.js)
- LMS integration (Canvas, Blackboard)
- Export to CSV/PDF with formatting
- Role-based access control (department admin)
- Form versioning & drafts
- Real-time collaboration (WebSockets)
- Mobile app (React Native)
Vector
GitHub: @HalcyonVector
Found a bug or have a feature request?
Open an issue on GitHub.
Made with β€οΈ for educators and students everywhere