A modern, production-ready blog platform built with Next.js 15 (frontend) and FastAPI (backend), featuring passwordless authentication, admin dashboard, and comprehensive content management.
- Modern Architecture: Built with Next.js 15 App Router, TypeScript, and Tailwind CSS v4
- Responsive Design: Mobile-first design with beautiful, accessible layouts
- Admin Dashboard: Complete content management system with rich text editor
- Dark/Light Theme: System preference detection with manual toggle support
- Search & Discovery: Full-text search with advanced tag filtering
- File Management: Drag-and-drop file upload with image optimization
- Real-time Updates: Optimistic UI updates with TanStack Query
- Authentication: Passwordless email-based authentication flow
- High Performance: FastAPI with async/await and Python 3.13+
- Type Safety: End-to-end type safety with Pydantic v2
- Email Authentication: Secure passwordless authentication system
- Permission System: Granular role-based access control
- File Storage: Secure file upload with validation and streaming
- Database Migrations: Alembic for schema versioning and management
- Rich Logging: Structured logging with beautiful terminal output
- API Documentation: Auto-generated OpenAPI/Swagger documentation
- Passwordless Auth: No password storage or management required
- Session Security: HTTP-only cookies with CSRF protection
- Input Validation: Comprehensive data validation on frontend and backend
- File Security: Type validation, size limits, and permission-based access
- Performance: Optimized queries, caching, and code splitting
frusablog/
βββ π backend/ # FastAPI Backend Application
β βββ π app/ # Main application package
β β βββ π api/ # API layer with versioning
β β β βββ π routes/v1/ # API version 1
β β β βββ controllers/ # FastAPI route handlers
β β β βββ dto/ # Data Transfer Objects (Pydantic models)
β β β βββ providers/ # Business logic layer
β β βββ π core/ # Core application components
β β β βββ config/ # Configuration management
β β β βββ db/ # Database models & setup
β β β βββ security/ # Authentication & permissions
β β β βββ services/ # External services (email, storage)
β β βββ π utils/ # Utility functions and helpers
β βββ π migrations/ # Alembic database migrations
β βββ π fs/storage/ # Local file storage directory
β βββ π assets/templates/ # Email and other templates
β βββ π main.py # Application entry point
β βββ π pyproject.toml # Python dependencies & project config
β βββ π docker-compose.yml # Development environment setup
β βββ π Dockerfile # Backend container configuration
β
βββ π frontend/ # Next.js Frontend Application
βββ π src/ # Source code directory
β βββ π app/ # Next.js App Router
β β βββ (main)/ # Public blog interface
β β βββ (auth)/ # Authentication pages
β β βββ (admin)/ # Admin dashboard & management
β βββ π components/ # Reusable React components
β β βββ ui/ # shadcn/ui components
β β βββ data/ # Data display components
β β βββ layouts/ # Layout and navigation components
β β βββ wrappers/ # HOCs and context providers
β βββ π lib/ # Libraries and configurations
β β βββ api/ # API client and TypeScript types
β β βββ config/ # Application configuration
β β βββ utils/ # Utility functions and helpers
β βββ π hooks/ # Custom React hooks
βββ π public/ # Static assets
βββ π package.json # Node.js dependencies
βββ π next.config.ts # Next.js configuration
βββ π tailwind.config.ts # Tailwind CSS configuration
βββ π Dockerfile # Frontend container configuration
- Controllers β HTTP request/response handling
- Providers β Business logic and orchestration
- Models β Database entities and relationships
- Services β External integrations (email, storage)
- Pages β App Router pages with layouts
- Components β Reusable UI components
- Hooks β Custom logic and state management
- Libraries β API clients and utilities
- Framework: Next.js 15 with App Router
- Language: TypeScript with strict mode
- Styling: Tailwind CSS v4 with custom design system
- UI Library: shadcn/ui with Radix UI primitives
- State Management: TanStack Query (React Query v5)
- Form Handling: React Hook Form with Zod validation
- Rich Text: MDEditor with React Markdown
- Icons: Lucide React icon library
- Theme System: next-themes
- Package Manager: pnpm or bun
- Framework: FastAPI with async/await
- Language: Python 3.13+ with type hints
- Database: PostgreSQL with SQLModel ORM
- Migrations: Alembic for database versioning
- Authentication: Custom email-based passwordless system
- File Storage: Local filesystem (extensible to cloud storage)
- Email Service: SMTP with Jinja2 templates
- Validation: Pydantic v2 for data validation
- Package Manager: UV for dependency management
- Code Quality: Ruff for linting and formatting
- Database: PostgreSQL 17 with optimized indexing
- Migration System: Alembic with automatic schema generation
- Development: Docker Compose for local development
- Deployment: Docker containers with multi-stage builds
- Monitoring: Health checks and structured logging
- Node.js 18+ and pnpm (or bun)
- Python 3.13+ and UV package manager
- PostgreSQL 17 (or Docker for development)
- Git for version control
The fastest way to get the entire stack running:
# Clone the repository
git clone https://github.com/frusadev/frusablog.git
cd frusablog
# Start the backend services (API + Database)
cd backend
docker-compose up --build -d
# In a new terminal, start the frontend
cd ../frontend
pnpm install
pnpm devπ Access the application:
- Frontend: http://localhost:3000
- Backend API: http://localhost:8000
- API Documentation: http://localhost:8000/docs
-
Navigate to backend directory
cd backend -
Install dependencies with UV
uv sync
-
Configure environment
cp .env.example .env # Edit .env with your configuration (see Environment Variables section) -
Set up PostgreSQL database
# Option 1: Use Docker for database only docker run --name frusablog-db -e POSTGRES_PASSWORD=password -e POSTGRES_DB=frusablog -p 5432:5432 -d postgres:17 # Option 2: Use local PostgreSQL installation createdb frusablog
-
Run database migrations
alembic upgrade head
-
Start the development server
python main.py
The API will be available at
http://localhost:8000π‘
-
Navigate to frontend directory
cd frontend -
Install dependencies
pnpm install # or with bun bun install -
Configure environment
# Create .env.local with API connection settings cat > .env.local << EOF NEXT_PUBLIC_SERVER_URL=http://localhost:8000 NEXT_PUBLIC_API_VERSION=v1 EOF
-
Start development server
pnpm dev # or with bun bun devThe application will be available at
http://localhost:3000π
- API Documentation - Complete API reference with examples
- Deployment Guide - Production deployment instructions
- Frontend README - Frontend-specific documentation
- Backend README - Backend setup and development
- Backend Developer Guide - Technical implementation details
- API Interactive Docs - Swagger UI (when running)
- Redoc API Docs - Alternative API documentation
- Database Schema - Data models and relationships
POST /v1/auth/email/register- User registration with emailPOST /v1/auth/email/login- Login request (sends magic link email)GET /v1/auth/email/authenticate/{session_id}- Complete authentication via email linkPOST /v1/auth/logout- Logout and clear session
GET /v1/posts- Get published posts (with pagination)GET /v1/posts/featured- Get featured postsGET /v1/posts/drafts- Get draft posts (authenticated)GET /v1/posts/search?q={query}- Search posts by title/contentGET /v1/post/{id}- Get specific post by IDPOST /v1/post- Create new post (authenticated)PUT /v1/post/{id}- Update post (authenticated)DELETE /v1/post/{id}- Delete post (authenticated)
GET /v1/comments/{post_id}- Get post comments with threadingPOST /v1/comment- Create comment (authenticated)PUT /v1/comment/{id}- Update comment (authenticated)DELETE /v1/comment/{id}- Delete comment (authenticated)POST /v1/comment/{id}/like- Like/unlike comment (authenticated)
POST /v1/resource- Upload single file (authenticated)POST /v1/resources- Upload multiple files (authenticated)GET /v1/resource/{id}- Download/view fileDELETE /v1/resource/{id}- Delete file (authenticated)
GET /v1/users/me- Get current user profile (authenticated)GET /v1/users/me/can-post- Check posting permissions (authenticated)PUT /v1/users/me- Update user profile (authenticated)
interface User {
id: string; // Unique user identifier
username: string; // Unique username
name: string; // Display name
email: string; // Email address (private)
created_at: datetime; // Account creation timestamp
roles: Role[]; // Assigned roles for permissions
}interface Post {
id: UUID; // Unique post identifier
title: string; // Post title (max 100 chars)
description: string; // Post description (max 400 chars)
content: string; // Markdown content
cover?: UUID; // Cover image file resource ID
likes: number; // Like count
published: boolean; // Publication status
archived: boolean; // Archive status
featured: boolean; // Featured status for homepage
created_at: datetime; // Creation timestamp
author: User; // Post author
tags: Tag[]; // Associated tags
comments: Comment[]; // Post comments
}interface Comment {
id: UUID; // Unique comment identifier
content: string; // Comment text
likes: number; // Like count
level: number; // Nesting level (0=top, 1=reply)
created_at: datetime; // Creation timestamp
author: User; // Comment author
post: Post; // Parent post
parent?: Comment; // Parent comment (for replies)
children: Comment[]; // Child comments
}interface Tag {
id: UUID; // Unique tag identifier
name: string; // Tag name (unique)
posts: Post[]; // Posts with this tag
}interface Role {
id: UUID;
name: string; // Role name (e.g., "admin", "user")
description: string;
users: User[]; // Users with this role
permissions: Permission[];
}
interface Permission {
id: UUID;
role: Role; // Associated role
resource_name: string; // Resource type (e.g., "post", "file")
resource_id?: string; // Specific resource ID (optional)
action_name: string; // Action type (e.g., "read", "write", "admin")
}interface AuthSession {
id: string; // Session identifier for email links
user: User; // Associated user
expires_at: datetime; // Expiration time (1 hour)
expired: boolean; // Manual expiration flag
}
interface LoginSession {
id: string; // Session identifier for cookies
user: User; // Associated user
expires_at: datetime; // Expiration time (30 days)
created_at: datetime; // Creation timestamp
}interface FileResource {
id: UUID; // Unique file identifier
name: string; // Original filename
filetype: string; // MIME type
protected: boolean; // Permission-based access
created_at: datetime; // Upload timestamp
owner: User; // File owner
}(main)- Public blog interface/- Homepage with featured and recent posts/posts- All posts with pagination and filtering/post/[slug]- Individual post view with comments/search- Search interface with filters
(auth)- Authentication flow/login- Email-based login request/register- User registration/authenticate/[session_id]- Magic link authentication
(admin)- Admin dashboard (authenticated)/admin- Posts management dashboard/admin/posts/new- Create new post/admin/posts/[id]/edit- Edit existing post/admin/files- File management interface
components/
βββ ui/ // shadcn/ui components (Button, Input, etc.)
βββ data/ // Data display components
β βββ PostCard // Post preview component
β βββ CommentThread // Comment system
β βββ TagList // Tag display
βββ layouts/ // Layout components
β βββ Navigation // Site navigation
β βββ Footer // Site footer
β βββ Sidebar // Content sidebar
βββ wrappers/ // HOCs and providers
βββ AuthGuard // Authentication protection
βββ ThemeProvider // Theme management
βββ QueryProvider // TanStack Query setup- Server State: TanStack Query for API data caching
- Global State: React Context for user and theme state
- Form State: React Hook Form with Zod validation
- Local State: useState for component-specific UI state
- Passwordless Authentication: Secure email-based magic link system
- Session Management: HTTP-only cookies with CSRF protection
- Role-Based Access Control: Granular permission system for resources
- Permission Inheritance: Admin role bypasses specific permission checks
- Session Expiration: Automatic cleanup of expired auth sessions
- Upload Validation: MIME type detection and file size restrictions
- Protected Resources: Permission-based file access control
- Secure Storage: UUID-based file naming to prevent enumeration
- Content-Type Validation: Server-side file type verification
- Access Logging: Comprehensive file access tracking
- Frontend Validation: Zod schema validation with TypeScript
- Backend Validation: Pydantic model validation with Python
- SQL Injection Prevention: Parameterized queries with SQLModel
- XSS Protection: HTML sanitization and CSP headers
- Input Sanitization: Comprehensive input cleaning and validation
- Type Safety: End-to-end type safety across the stack
- Content Management: Create, edit, delete, and organize blog posts
- Draft System: Save and manage unpublished content with auto-save
- Featured Posts: Highlight important content on homepage
- Tag Management: Create and organize content categories
- File Upload: Drag-and-drop file management with image preview
- Analytics: View post performance and engagement metrics
- Search & Filter: Advanced content discovery and organization tools
- Markdown Support: Full GitHub-flavored markdown syntax
- Live Preview: Real-time split-pane preview mode
- Syntax Highlighting: Code block highlighting with multiple languages
- Image Embedding: Direct image uploads with automatic optimization
- Table Support: Rich table editing and formatting
- Link Management: Easy link insertion and validation
- Auto-Save: Automatic draft saving to prevent data loss
- Nested Threading: Two-level comment threading for discussions
- Like System: User engagement tracking with optimistic updates
- Real-time Updates: Live comment updates without page refresh
- Moderation Tools: Admin comment management and spam protection
- User Mentions: @mention system for user notifications
- Comment Editing: Edit and delete capabilities with version history
- Beautiful Templates: Responsive HTML email templates with Jinja2
- Authentication Emails: Secure magic link emails for login/registration
- Welcome Series: Automated welcome email sequence for new users
- Notification System: Comment and mention notifications
- Template Management: Easy email template customization
- Delivery Tracking: Email delivery status and analytics
# Frontend quality checks
cd frontend
pnpm lint # ESLint with TypeScript rules
pnpm format # Prettier code formatting
pnpm type-check # TypeScript strict mode checking
pnpm test # Jest with React Testing Library
pnpm test:e2e # Playwright end-to-end tests
# Backend quality checks
cd backend
ruff check # Fast Python linting
ruff format # Code formatting
pytest # Comprehensive test suite
pytest --cov=app # Coverage reporting
mypy app/ # Type checking- Frontend: Optimized for Vercel, Netlify, or Docker deployment
- Backend: Docker containerization with multi-stage builds
- Database: PostgreSQL with connection pooling and migrations
- CDN: Static asset optimization and caching
- Docker Compose: Complete local development stack
- Hot Reload: Live reload for both frontend and backend
- Database Seeding: Sample data for development and testing
- Next.js App Router: Latest routing with automatic code splitting
- Image Optimization: Next.js Image component with lazy loading
- Bundle Optimization: Tree shaking and dead code elimination
- Caching Strategy: TanStack Query with intelligent cache invalidation
- Lazy Loading: Component-level lazy loading for better LCP
- Static Generation: ISR (Incremental Static Regeneration) for posts
- Web Vitals: Optimized Core Web Vitals scores
- Async Architecture: Full async/await implementation with uvloop
- Database Optimization: Efficient SQLModel queries with eager loading
- Connection Pooling: PostgreSQL connection pool management
- Response Streaming: Efficient file serving with range requests
- Query Optimization: Strategic database indexing and query planning
- Background Tasks: Non-blocking email and file processing
- Health Monitoring: Performance metrics and monitoring endpoints
# Database
DB_STRING=postgresql+psycopg2://user:pass@localhost:5432/frusablog
ALEMBIC_DB_URL=postgresql+psycopg2://user:pass@localhost:5432/frusablog
# Application
DEBUG=True
PORT=8000
STORAGE=fs/storage
# Email (for authentication)
EMAIL_APP_PASSWORD=your-app-password
APP_EMAIL_ADDRESS=your-email@domain.com
EMAIL_TEMPLATES_PATH=assets/templates/email/
# URLs
FRONTEND_URL=http://localhost:3000
BACKEND_URL=http://localhost:8000# API Configuration
NEXT_PUBLIC_SERVER_URL=http://localhost:8000
NEXT_PUBLIC_API_VERSION=v1
NEXT_PUBLIC_API_URL=http://localhost:8000/v1
# Optional: Analytics and monitoring
NEXT_PUBLIC_ANALYTICS_ID=your-analytics-id
NEXT_PUBLIC_SENTRY_DSN=your-sentry-dsnWe welcome contributions! Here's how to get started:
-
π΄ Fork the repository
# Click "Fork" on GitHub, then clone your fork git clone https://github.com/YOUR_USERNAME/frusablog.git cd frusablog
-
πΏ Create a feature branch
git checkout -b feature/amazing-feature # or for bug fixes git checkout -b bugfix/issue-description -
π» Make your changes
- Follow the existing code style and patterns
- Add tests for new functionality
- Update documentation as needed
-
π§ͺ Run quality checks
# Backend checks cd backend ruff check && ruff format pytest # Frontend checks cd ../frontend pnpm lint && pnpm type-check pnpm test
-
π Commit with conventional commits
git commit -m "feat: add amazing new feature" # or git commit -m "fix: resolve login issue" # or git commit -m "docs: update API documentation"
-
π Push and create PR
git push origin feature/amazing-feature # Then create a Pull Request on GitHub
- Code Style: Follow existing patterns and use the configured linters
- Testing: Add tests for new features and ensure existing tests pass
- Documentation: Update relevant documentation for API or feature changes
- Commit Messages: Use conventional commits (feat, fix, docs, etc.)
- Pull Requests: Provide clear description of changes and link any issues
- Bug Reports: Use the GitHub issue template with reproduction steps
- Feature Requests: Describe the feature and its use case clearly
- Security Issues: Report privately via email first
# Database connection issues
β Error: "could not connect to server"
β
Solution: Ensure PostgreSQL is running and credentials are correct
docker ps # Check if database container is running
docker-compose logs db # Check database logs
# Migration errors
β Error: "Target database is not up to date"
β
Solution: Run migrations
alembic upgrade head
# Email configuration issues
β Error: "Authentication failed" for SMTP
β
Solution: Check email app password and SMTP settings
# For Gmail, use App Password, not regular password# Port conflicts
β Error: "Port already in use"
β
Solution: Stop conflicting services or change ports
docker-compose down
lsof -i :8000 # Check what's using the port
# Volume permission issues
β Error: "Permission denied" for file uploads
β
Solution: Fix volume permissions
docker-compose down
sudo chown -R $USER:$USER backend/fs
docker-compose up- π Documentation: Check the API.md and component READMEs
- π Issues: Search existing issues or create a new one
- π¬ Discussions: Use GitHub Discussions for questions
- π§ Email: Contact @frusadev for urgent issues
This project is licensed under the MIT License - see the LICENSE file for details.
- Next.js 15 Documentation - Next.js framework documentation
- FastAPI Documentation - FastAPI framework guide
- shadcn/ui Components - UI component library
- TanStack Query - Data fetching and caching
- SQLModel Documentation - Database ORM
- Tailwind CSS - CSS framework
- UV Documentation - Python package manager
- Ruff Documentation - Python linter
- Alembic Documentation - Database migrations
- pnpm Documentation - Node.js package manager
- Vercel - Frontend deployment platform
- Railway - Full-stack deployment
- Docker Hub - Container registry
- PostgreSQL Cloud - Database hosting
π¨βπ» Developer: Daniel Ametsowou
π GitHub: @frusadev
π Project: https://github.com/frusadev/frusablog
- π Bug Reports: GitHub Issues
- π¬ Discussions: GitHub Discussions
- π§ Direct Contact: Open an issue for feature requests or questions