Complete API documentation for the Research Organization Template.
Authenticate a user with email and password.
Location: src/app/(withoutNavbar)/login/actions.ts
Parameters:
email(string) - User email addresspassword(string) - User password
Returns:
{ error?: string }Example:
const formData = new FormData()
formData.append('email', 'user@example.com')
formData.append('password', 'password123')
const result = await login(formData)
if (result.error) {
console.error(result.error)
}Errors:
"Email and password are required"- Missing credentials"Please check your email and confirm your account"- Email not confirmed"Invalid email or password"- Authentication failed
Create a new user account.
Location: src/app/(withoutNavbar)/signup/actions.ts
Parameters:
email(string) - User email addresspassword(string) - User password (min 8 characters)
Returns:
{ error?: string }Example:
const formData = new FormData()
formData.append('email', 'newuser@example.com')
formData.append('password', 'securepassword123')
const result = await signup(formData)Note: New users are automatically assigned the member role.
Sign out the current user.
Returns:
- Redirects to
/login
Example:
await fetch('/api/auth/signout', { method: 'POST' })Create or update a project. Admin/Manager only.
Location: src/app/(withoutNavbar)/dashboard/admin/projects/actions.ts
Parameters:
id(string, optional) - Project ID for updatestitle(string) - Project titleslug(string) - URL-friendly slug (unique)description(string) - Project descriptionproject_type(string) - Type:research_paper,software,experiment,dataset,othercategory_id(string, optional) - Category UUIDstatus(string) -active,completed, orarchivedtags(string) - Comma-separated tagsgithub_url(string, optional) - GitHub repository URLdemo_url(string, optional) - Demo URLpaper_url(string, optional) - Research paper URLdocumentation_url(string, optional) - Documentation URLauthors(string) - Comma-separated author namespublication_venue(string, optional) - Publication venuepublication_year(number, optional) - Publication yeardoi(string, optional) - DOIpublished_at(string, optional) - ISO date string for publishing
Returns:
{ error?: string, projectId?: string }Example:
const formData = new FormData()
formData.append('title', 'My Research Project')
formData.append('slug', 'my-research-project')
formData.append('description', 'A groundbreaking research project')
formData.append('project_type', 'research_paper')
formData.append('status', 'active')
formData.append('tags', 'AI, Machine Learning, Research')
formData.append('published_at', new Date().toISOString())
const result = await saveProject(formData)Errors:
"Not authenticated"- User not logged in"Only admins and managers can manage projects"- Insufficient permissions"Project with this slug already exists"- Duplicate slug
Delete a project. Admin/Manager only.
Location: src/app/(withoutNavbar)/dashboard/admin/projects/actions.ts
Parameters:
projectId(string) - Project UUID
Returns:
{ error?: string }Create a new discussion post. Authenticated users only.
Location: src/app/api/community/posts/actions.ts
Parameters:
interface CreatePostParams {
title: string
content: string
categoryId?: string | null
projectId?: string | null
}Returns:
{ error?: string, success?: boolean, postId?: string }Example:
const result = await createPost({
title: 'Discussion about AI',
content: 'What are your thoughts on...',
categoryId: 'category-uuid',
projectId: 'project-uuid' // optional
})Create a comment on a post or reply to a comment. Authenticated users only.
Location: src/app/api/community/comments/actions.ts
Parameters:
interface CreateCommentParams {
postId: string
parentCommentId?: string // For nested replies
content: string
}Returns:
{ error?: string, success?: boolean, comment?: Comment }Example:
// Top-level comment
const result = await createComment({
postId: 'post-uuid',
content: 'Great post!'
})
// Reply to comment
const reply = await createComment({
postId: 'post-uuid',
parentCommentId: 'comment-uuid',
content: 'I agree!'
})Vote on a post or comment. Authenticated users only.
Location: src/app/api/community/vote/actions.ts
Parameters:
interface VoteParams {
targetId: string // Post or comment ID
type: 'post' | 'comment'
voteType: 1 | -1 // 1 for upvote, -1 for downvote
}Returns:
{ error?: string, voteScore?: number, userVote?: 1 | -1 | null }Example:
// Upvote a post
const result = await vote({
targetId: 'post-uuid',
type: 'post',
voteType: 1
})
// Downvote a comment
const result = await vote({
targetId: 'comment-uuid',
type: 'comment',
voteType: -1
})Behavior:
- Clicking the same vote again removes the vote (toggles off)
- Clicking the opposite vote changes the vote
- Vote scores are automatically recalculated
Update a user's role. Admin only.
Location: src/app/(withoutNavbar)/dashboard/admin/roles/actions.ts
Parameters:
userId(string) - User UUIDnewRole(string) -'admin','manager', or'member'
Returns:
{ error?: string }Example:
const result = await updateUserRole('user-uuid', 'manager')
if (result.error) {
console.error(result.error)
}Errors:
"Not authenticated"- User not logged in"Only admins can change user roles"- Insufficient permissions"Invalid role"- Role not in allowed list"You cannot remove your own admin role"- Self-protection
List all users with their roles. Admin only.
Returns:
{
users: Array<{
id: string
role: 'admin' | 'manager' | 'member'
created_at: string
}>
}Example:
const response = await fetch('/api/admin/users', {
headers: {
'Cookie': document.cookie
}
})
const data = await response.json()Status Codes:
200- Success401- Not authenticated403- Not admin
Send an email via the contact form. Optional - requires Resend API key.
Location: src/app/api/send/route.ts
Request Body:
{
firstname: string
lastname: string
email: string
message: string
}Returns:
{ data?: EmailResponse, error?: string }Example:
const response = await fetch('/api/send', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
firstname: 'John',
lastname: 'Doe',
email: 'john@example.com',
message: 'Hello!'
})
})Environment Variables:
RESEND_API_KEY- Required for email functionality
Note: Update the recipient email in src/app/api/send/route.ts (line 18).
All types are available in src/utils/types.ts:
import {
Project,
DiscussionPost,
DiscussionComment,
Category,
UserRole,
ProjectStatus,
VoteType
} from '@/utils/types'Application constants are in src/utils/constants.ts:
import {
ROLES,
PROJECT_STATUS,
PROJECT_TYPES,
ROUTES,
VALIDATION
} from '@/utils/constants'All API endpoints and server actions return errors in a consistent format:
{ error: string }Common Error Messages:
"Not authenticated"- User must be logged in"Forbidden"- User lacks required permissions"Not found"- Resource doesn't exist"Invalid input"- Validation failed
Most endpoints require authentication. The application uses:
- Supabase Auth - Session-based authentication
- Server-side verification - All protected routes verify auth server-side
- Role-based access - Admin/Manager/Member roles enforced
Getting Current User:
import { createClient } from '@/utils/supabase/server'
const supabase = await createClient()
const { data: { user } } = await supabase.auth.getUser()
if (!user) {
// Not authenticated
}Checking Roles:
import { requireRole, getUserRole } from '@/utils/roles'
const role = await getUserRole(user.id)
const isAdmin = await requireRole(user.id, ['admin'])Currently, the application relies on Supabase's built-in rate limiting:
- Free tier: 500 requests per second per project
- Pro tier: Higher limits
For production, consider implementing additional rate limiting for:
- Email sending
- Vote actions
- Comment creation
- ✅ Always verify authentication - Check user on server-side
- ✅ Verify roles server-side - Never trust client-side role checks
- ✅ Use RLS policies - Database-level security
- ✅ Validate input - Sanitize user input
- ✅ Use parameterized queries - Supabase handles this automatically
- ✅ HTTPS only - All deployments use HTTPS
Use the browser console or tools like Postman:
// Example: Create a post
const formData = new FormData()
formData.append('title', 'Test Post')
formData.append('content', 'Test content')
const response = await fetch('/api/community/posts', {
method: 'POST',
body: formData
})Test server actions directly:
import { createPost } from '@/app/api/community/posts/actions'
const result = await createPost({
title: 'Test',
content: 'Test content'
})- Review Setup Guide for database configuration
- Check Deployment Guide for production setup
- Explore the codebase for implementation details
Need help? Open an issue on GitHub or check the documentation.