Initial commit in this repository

This commit is contained in:
Rapturate
2026-04-27 22:16:17 -04:00
commit 68e7058ca4
64 changed files with 20817 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 215 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

53
docs/design/Roadmap Normal file
View File

@@ -0,0 +1,53 @@
# IDEA TRACKER API - DEVELOPMENT ROADMAP
# PHASE 1: MIDDLEWARE & VALIDATION
[x] Create authMiddleware.js - JWT verification and user authentication
[x] Create validateIdeas.js - Request validation for idea endpoints - Validate POST: name (3+ chars), description (required) - Validate PUT: same as POST, but both optional - Validate param id as positive integer
[x] Create validateProjects.js - Request validation for project endpoints - Validate POST: name (3+ chars), description (required) - Validate PUT: same as POST, but both optional - Validate param id as positive integer
[x] Create validateMaterials.js - Request validation for material endpoints - Validate POST: projectId, name, description, source, author, text (all required) - Validate DELETE: param id as positive integer
[x] Update/Review handleValidationErrors.js to ensure proper error responses
# PHASE 2: REPOSITORY LAYER (DATA ACCESS)
[x] Create ideasRepo.js - getAll(userId) - fetch all user ideas - getById(ideaId, userId) - fetch single idea with ownership check - create(userId, { name, description }) - update(ideaId, userId, { name, description }) - delete(ideaId, userId) - existsByName(userId, name) - check for duplicates
[x] Create projectsRepo.js - getAll(userId) - getById(projectId, userId) - create(userId, { name, description }) - update(projectId, userId, { name, description }) - delete(projectId, userId) - existsByName(userId, name)
[x] Create materialsRepo.js - getAll(userId) - all user materials - getByProjectId(projectId, userId) - materials for specific project - getById(materialId, userId) - single material with access check - create(userId, { projectId, name, description, source, author, text }) - delete(materialId, userId) - existsByName(userId, name)
# PHASE 3: SERVICE LAYER (BUSINESS LOGIC)
[x] Create ideasService.js - getAllIdeas(userId) - getIdeaById(ideaId, userId) - with 404 handling - createIdea(userId, { name, description }) - with duplicate check (409) - updateIdea(ideaId, userId, { name, description }) - with duplicate check - deleteIdea(ideaId, userId) - with 404 handling
[x] Create projectsService.js - Same methods as ideas service
[x] Create materialsService.js - getAllMaterials(userId) - getMaterialsByProject(projectId, userId) - createMaterial(userId, { projectId, name, description, source, author, text }) - deleteMaterial(materialId, userId) - Include project existence validation before creating material
# PHASE 4: CONTROLLER LAYER (REQUEST HANDLERS)
[x] Create ideasController.js - getAll(req, res) - GET /api/ideas - getById(req, res) - GET /api/ideas/:id - create(req, res) - POST /api/ideas - update(req, res) - PUT /api/ideas/:id - delete(req, res) - DELETE /api/ideas/:id
[x] Create projectsController.js - getAll(req, res) - GET /api/projects - getById(req, res) - GET /api/projects/:id - create(req, res) - POST /api/projects - update(req, res) - PUT /api/projects/:id - delete(req, res) - DELETE /api/projects/:id
[x] Create materialsController.js - getAll(req, res) - GET /api/materials - getByProject(req, res) - GET /api/materials/:projectId - create(req, res) - POST /api/materials - delete(req, res) - DELETE /api/materials/:id
# PHASE 5: ROUTES
[x] Create ideasRoutes.js - Route all endpoints with validation & auth middleware
[x] Create projectsRoutes.js - Route all endpoints with validation & auth middleware
[x] Create materialsRoutes.js - Route all endpoints with validation & auth middleware
# PHASE 6: UPDATE SERVER
[x] Update server.js - Replace /api/posts with /api/ideas - Add /api/projects routes - Add /api/materials routes
# PHASE 7: TESTING
[X] Test all endpoints with Swagger
[X] Verify JWT auth on protected routes
[x] Test 404, 409, 403 error cases
[X] Run seed script: npm run seed
[X] Verify Prettier formatting: npx prettier --write .
# PHASE 8: POLISH
[X] Write swagger for pagination
[X] Write code for POST project Files (within projects layers)
[X] Write code for DELETE project Files (within projects layers)
[X] Edit swagger to show an option for "upload a file to this project"
[X] create a path for downloading all files related to a project

BIN
docs/design/Roadmap.docx Normal file

Binary file not shown.

699
docs/openapi.yaml Normal file
View File

@@ -0,0 +1,699 @@
openapi: 3.1.0
info:
title: Idea Tracker API
version: 1.0.0
description: A REST API for managing project ideas, projects, materials, and files
servers:
- url: http://localhost:8080
description: Local development server
tags:
- name: Authentication
description: User authentication endpoints
- name: Ideas
description: Idea management endpoints
- name: Projects
description: Project management endpoints
- name: Materials
description: Project materials and resources
paths:
/api/auth/signup:
post:
summary: Create a new user account
tags:
- Authentication
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/SignupRequest'
responses:
'201':
description: User created successfully
content:
application/json:
schema:
$ref: '#/components/schemas/UserResponse'
'400':
description: Invalid input or validation error
'409':
description: Username already exists
/api/auth/login:
post:
summary: Login and receive JWT token
tags:
- Authentication
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/LoginRequest'
responses:
'200':
description: Login successful
content:
application/json:
schema:
$ref: '#/components/schemas/LoginResponse'
'401':
description: Invalid credentials
/api/ideas:
get:
summary: Get all ideas for the authenticated user
tags:
- Ideas
security:
- BearerAuth: []
responses:
'200':
description: OK
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Idea'
'401':
description: Unauthorized - Missing or invalid token
post:
summary: Create a new idea
tags:
- Ideas
security:
- BearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/IdeaRequest'
responses:
'201':
description: Idea created successfully
content:
application/json:
schema:
$ref: '#/components/schemas/Idea'
'400':
description: Bad Request - Validation error
'401':
description: Unauthorized - Missing or invalid token
'409':
description: Conflict - Idea with that name already exists
/api/ideas/{id}:
put:
summary: Update an idea
tags:
- Ideas
security:
- BearerAuth: []
parameters:
- name: id
in: path
required: true
schema:
type: integer
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/IdeaUpdateRequest'
responses:
'200':
description: Idea updated successfully
content:
application/json:
schema:
$ref: '#/components/schemas/Idea'
'400':
description: Bad Request - Id not a positive integer, or no fields provided
'401':
description: Unauthorized - Missing or invalid token
'404':
description: Not Found - No idea with that id belongs to this user
'409':
description: Conflict - Idea with that name already exists
delete:
summary: Delete an idea
tags:
- Ideas
security:
- BearerAuth: []
parameters:
- name: id
in: path
required: true
schema:
type: integer
responses:
'204':
description: Idea deleted successfully
'400':
description: Bad Request - Id not a positive integer
'401':
description: Unauthorized - Missing or invalid token
'404':
description: Not Found - No idea with that id belongs to this user
/api/projects:
get:
summary: Get all projects for the authenticated user
tags:
- Projects
security:
- BearerAuth: []
responses:
'200':
description: OK
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Project'
'401':
description: Unauthorized - Missing or invalid token
post:
summary: Create a new project
tags:
- Projects
security:
- BearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ProjectRequest'
responses:
'201':
description: Project created successfully
content:
application/json:
schema:
$ref: '#/components/schemas/Project'
'400':
description: Bad Request - Validation error
'401':
description: Unauthorized - Missing or invalid token
'409':
description: Conflict - Project with that name already exists
/api/projects/{id}:
get:
summary: Get a project by ID
tags:
- Projects
security:
- BearerAuth: []
parameters:
- name: id
in: path
required: true
schema:
type: integer
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/Project'
'400':
description: Bad Request - Id not a positive integer
'401':
description: Unauthorized - Missing or invalid token
'404':
description: Not Found - No project with that id belongs to this user
put:
summary: Update a project
tags:
- Projects
security:
- BearerAuth: []
parameters:
- name: id
in: path
required: true
schema:
type: integer
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ProjectUpdateRequest'
responses:
'200':
description: Project updated successfully
content:
application/json:
schema:
$ref: '#/components/schemas/Project'
'400':
description: Bad Request - Id not a positive integer, or no fields provided
'401':
description: Unauthorized - Missing or invalid token
'404':
description: Not Found - No project with that id belongs to this user
'409':
description: Conflict - Project with that name already exists
delete:
summary: Delete a project
tags:
- Projects
security:
- BearerAuth: []
parameters:
- name: id
in: path
required: true
schema:
type: integer
responses:
'204':
description: Project deleted successfully
'400':
description: Bad Request - Id not a positive integer
'401':
description: Unauthorized - Missing or invalid token
'404':
description: Not Found - No project with that id belongs to this user
/api/projects/{id}/files:
get:
summary: List all files related to a project
tags:
- Projects
security:
- BearerAuth: []
parameters:
- name: id
in: path
required: true
schema:
type: integer
responses:
'200':
description: OK
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/File'
'400':
description: Bad Request - Id not a positive integer
'401':
description: Unauthorized - Missing or invalid token
'404':
description: Not Found - No project with that id belongs to this user
post:
summary: Upload a file (Max 10MB)
tags: [Projects]
security: [{ BearerAuth: [] }]
parameters:
- $ref: '#/components/parameters/IdParam'
requestBody:
content:
multipart/form-data:
schema:
type: object
properties:
file:
type: string
format: binary
responses:
'201':
description: File uploaded
'400':
description: Bad Request - Id not a positive integer
'401':
description: Unauthorized - Missing or invalid token
'404':
description: Not Found - No project with that id belongs to this user
'413':
description: Payload Too Large - File size exceeds 10MB limit
/api/projects/files/{fileId}:
delete:
summary: Delete a specific project file
tags: [Projects]
security: [{ BearerAuth: [] }]
parameters:
- name: fileId
in: path
required: true
schema:
type: integer
responses:
'204':
description: File deleted
'404':
description: Not Found or Unauthorized
/api/projects/{id}/files/download:
get:
summary: Download all project files as a ZIP
tags: [Projects]
security: [{ BearerAuth: [] }]
parameters:
- $ref: '#/components/parameters/IdParam'
responses:
'200':
description: A ZIP file containing all project documents
content:
application/zip:
schema:
type: string
format: binary
/api/materials:
get:
summary: Get all materials for the authenticated user
tags:
- Materials
security:
- BearerAuth: []
responses:
'200':
description: OK
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Material'
'401':
description: Unauthorized - Missing or invalid token
post:
summary: Create a new material
tags:
- Materials
security:
- BearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/MaterialRequest'
responses:
'201':
description: Material created successfully
content:
application/json:
schema:
$ref: '#/components/schemas/Material'
'400':
description: Bad Request - Validation error
'401':
description: Unauthorized - Missing or invalid token
'409':
description: Conflict - Material with that name already exists
/api/materials/project/{projectId}:
get:
summary: Get all materials for a specific project
tags:
- Materials
security:
- BearerAuth: []
parameters:
- name: projectId
in: path
required: true
schema:
type: integer
responses:
'200':
description: OK
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Material'
'400':
description: Bad Request - projectId not a positive integer
'401':
description: Unauthorized - Missing or invalid token
/api/materials/{id}:
delete:
summary: Delete a material by ID
tags:
- Materials
security:
- BearerAuth: []
parameters:
- name: id
in: path
required: true
schema:
type: integer
responses:
'204':
description: Material deleted successfully
'400':
description: Bad Request - Id not a positive integer
'401':
description: Unauthorized - Missing or invalid token
'404':
description: Not Found - No material with that id belongs to this user
components:
securitySchemes:
BearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
parameters:
IdParam:
name: id
in: path
required: true
schema: { type: integer }
SearchQuery:
name: search
in: query
schema: { type: string }
SortBy:
name: sortBy
in: query
schema: { type: string, enum: [name, date_created, id] }
Limit:
name: limit
in: query
schema: { type: integer, default: 10 }
Offset:
name: offset
in: query
schema: { type: integer, default: 0 }
schemas:
SignupRequest:
type: object
required:
- username
- password
properties:
username:
type: string
example: new_user_1
password:
type: string
format: password
example: newpassword1234
LoginRequest:
type: object
required:
- username
- password
properties:
username:
type: string
example: new_user_1
password:
type: string
format: password
example: newpassword1234
UserResponse:
type: object
properties:
id:
type: integer
example: 10
username:
type: string
example: new_user_1
LoginResponse:
type: object
properties:
accessToken:
type: string
example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Idea:
type: object
properties:
id:
type: integer
readOnly: true
example: 1
name:
type: string
example: AI-Powered Task Manager
description:
type: string
example: A web app that uses AI to prioritize tasks intelligently
date_created:
type: string
format: date-time
readOnly: true
IdeaRequest:
type: object
required:
- name
- description
properties:
name:
type: string
example: AI-Powered Task Manager
description:
type: string
example: A web app that uses AI to prioritize tasks intelligently
IdeaUpdateRequest:
type: object
description: At least one field must be provided
properties:
name:
type: string
example: AI-Powered Task Manager
description:
type: string
example: A web app that uses AI to prioritize tasks intelligently
Project:
type: object
properties:
id:
type: integer
readOnly: true
example: 1
name:
type: string
example: Project 1
description:
type: string
example: Project 1 description
date_created:
type: string
format: date-time
readOnly: true
files:
type: array
readOnly: true
items:
$ref: '#/components/schemas/File'
ProjectRequest:
type: object
required:
- name
- description
properties:
name:
type: string
example: Project 1
description:
type: string
example: Project 1 description
ProjectUpdateRequest:
type: object
description: At least one field must be provided
properties:
name:
type: string
example: Project 1
description:
type: string
example: Project 1 description
Material:
type: object
properties:
id:
type: integer
readOnly: true
example: 1
projectId:
type: integer
example: 1
name:
type: string
example: Resource 1
description:
type: string
example: Resource 1 description
source:
type: string
example: Source 1
author:
type: string
example: Author 1
text:
type: string
example: Resource 1 text
MaterialRequest:
type: object
required:
- projectId
- name
- description
- source
- author
- text
properties:
projectId:
type: integer
example: 1
name:
type: string
example: Resource 1
description:
type: string
example: Resource 1 description
source:
type: string
example: Source 1
author:
type: string
example: Author 1
text:
type: string
example: Resource 1 text
File:
type: object
properties:
id: { type: integer }
projectId: { type: integer }
name: { type: string }
size: { type: integer }
mimeType: { type: string }