diff --git a/README.md b/README.md index 813bc9e..24826e1 100644 --- a/README.md +++ b/README.md @@ -2,14 +2,41 @@ A production-ready Next.js 16 application with database management capabilities, built with TypeScript, Tailwind CSS, and DrizzleORM for connecting to multiple database backends. +## ๐Ÿ—๏ธ Configuration-Driven Architecture + +This project features a **unique JSON-driven architecture** that makes adding features incredibly simple: + +- **Define features in JSON** (`src/config/features.json`) - no need to write boilerplate code +- **Automatic UI generation** - navigation and forms are generated by looping over configuration +- **Reusable components** - shared `DataGrid`, `FormDialog`, and `ConfirmDialog` components +- **Feature flags** - enable/disable features with a single boolean in the config +- **Type-safe** - TypeScript ensures configuration integrity + +**Example**: To add a new feature, simply add an entry to `features.json`: + +```json +{ + "id": "my-feature", + "name": "My Feature", + "enabled": true, + "endpoints": [...], + "ui": { "showInNav": true, "icon": "Star", "actions": ["create", "read"] } +} +``` + +The system automatically generates the navigation item, API routes, and UI components! + ## Overview This project is a full-stack web application featuring: - **Next.js 16** with App Router for server-side rendering and static site generation +- **Configuration-driven architecture** - Features defined in JSON, UI generated automatically +- **Database CRUD operations** - Create, read, update, and delete records through a clean UI - **DrizzleORM** for type-safe database operations with support for PostgreSQL, MySQL, and SQLite - **PostgreSQL 15** included as default database in Docker container - **Multi-database support** - Connect to external PostgreSQL, MySQL, or SQLite servers -- **Authentication** using Clerk with support for multiple auth providers +- **Admin panel** with authentication, table management, and SQL query interface +- **Authentication** using JWT with secure session management - **TypeScript** for type safety across the entire stack - **Tailwind CSS 4** for modern, responsive styling - **Docker** support for easy deployment @@ -18,12 +45,17 @@ This project is a full-stack web application featuring: ## Features - โšก **Next.js 16** with App Router support +- ๐Ÿ—๏ธ **Configuration-Driven Architecture** - Define features in JSON, auto-generate UI - ๐Ÿ”ฅ **TypeScript** for type safety - ๐Ÿ’Ž **Tailwind CSS 4** for styling -- ๐Ÿ”’ **Clerk Authentication** with social login support +- ๐Ÿ—„๏ธ **Database CRUD Operations** - Full Create, Read, Update, Delete functionality +- ๐Ÿ› ๏ธ **Admin Panel** - Manage tables, columns, and data through a beautiful UI +- ๐Ÿ“Š **SQL Query Interface** - Execute custom queries with safety validation +- ๐Ÿ”’ **JWT Authentication** with secure session management - ๐Ÿ“ฆ **DrizzleORM** - Support for PostgreSQL, MySQL, and SQLite - ๐Ÿ”Œ **Multi-Database Support** - Connect to custom database servers - ๐Ÿณ **Docker** with included PostgreSQL 15 (default option) +- โ™ป๏ธ **Reusable Components** - DataGrid, FormDialog, ConfirmDialog for consistent UX - ๐Ÿงช **Testing Suite** - Vitest for unit tests, Playwright for E2E - ๐ŸŽจ **Storybook** for UI component development - ๐Ÿ“ **ESLint & Prettier** for code quality @@ -57,14 +89,17 @@ Create a `.env.local` file: # Database DATABASE_URL=postgresql://docker:docker@localhost:5432/postgres -# Clerk Authentication -NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=your_key -CLERK_SECRET_KEY=your_secret +# JWT Secret (required for admin authentication) +JWT_SECRET=your_secure_random_secret_here # Optional: Admin user creation CREATE_ADMIN_USER=true ADMIN_USERNAME=admin ADMIN_PASSWORD=admin123 + +# Optional: Clerk Authentication +NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=your_key +CLERK_SECRET_KEY=your_secret ``` 4. Run the development server: @@ -74,6 +109,21 @@ npm run dev 5. Open http://localhost:3000 in your browser. +### Admin Panel + +Access the admin panel at http://localhost:3000/admin/login + +**Default credentials** (if using db:seed-admin): +- Username: `admin` +- Password: `admin123` (change this in production!) + +**Features available in the admin panel**: +- ๐Ÿ“Š **Table Browser**: View all database tables and their data +- โœ๏ธ **CRUD Operations**: Create, edit, and delete records +- ๐Ÿ” **SQL Query Interface**: Execute custom SELECT queries +- ๐Ÿ› ๏ธ **Schema Inspector**: View table structures, columns, and relationships +- ๐Ÿ” **Secure Access**: JWT-based authentication with session management + ### Docker Deployment The Docker container includes PostgreSQL 15 as the default database option. You can also connect to external database servers. @@ -103,9 +153,17 @@ The Docker container includes both PostgreSQL and the Next.js application, but P ``` โ”œโ”€โ”€ src/ โ”‚ โ”œโ”€โ”€ app/ # Next.js App Router pages +โ”‚ โ”‚ โ”œโ”€โ”€ admin/ # Admin panel pages (dashboard, login) +โ”‚ โ”‚ โ””โ”€โ”€ api/admin/ # Admin API routes (CRUD, tables, queries) โ”‚ โ”œโ”€โ”€ components/ # React components +โ”‚ โ”‚ โ””โ”€โ”€ admin/ # Reusable admin components (DataGrid, FormDialog, etc.) +โ”‚ โ”œโ”€โ”€ config/ # Configuration files +โ”‚ โ”‚ โ””โ”€โ”€ features.json # Feature definitions (JSON-driven architecture) โ”‚ โ”œโ”€โ”€ models/ # Database models (DrizzleORM schemas) โ”‚ โ”œโ”€โ”€ utils/ # Utility functions +โ”‚ โ”‚ โ”œโ”€โ”€ featureConfig.ts # Feature configuration loader +โ”‚ โ”‚ โ”œโ”€โ”€ db.ts # Database connection +โ”‚ โ”‚ โ””โ”€โ”€ session.ts # JWT session management โ”‚ โ”œโ”€โ”€ libs/ # Third-party library configurations โ”‚ โ””โ”€โ”€ locales/ # i18n translations โ”œโ”€โ”€ tests/ @@ -117,6 +175,69 @@ The Docker container includes both PostgreSQL and the Next.js application, but P โ””โ”€โ”€ docker-compose.yml # Docker Compose setup ``` +## Configuration-Driven Features + +### Adding a New Feature + +To add a new feature to the admin panel: + +1. **Define the feature in `src/config/features.json`**: +```json +{ + "id": "my-new-feature", + "name": "My New Feature", + "description": "Description of what it does", + "enabled": true, + "priority": "high", + "endpoints": [ + { + "path": "/api/admin/my-feature", + "methods": ["GET", "POST"], + "description": "API endpoint description" + } + ], + "ui": { + "showInNav": true, + "icon": "Settings", + "actions": ["create", "read", "update", "delete"] + } +} +``` + +2. **Add navigation item to `navItems` array** (if needed): +```json +{ + "id": "my-feature", + "label": "My Feature", + "icon": "Settings", + "featureId": "my-new-feature" +} +``` + +3. **Create API route** at `src/app/api/admin/my-feature/route.ts` + +4. **The UI is automatically generated** from your configuration! + +### Reusable Components + +Use these components for consistent UX: + +- **``** - Display table data with edit/delete actions +- **``** - Create/edit forms with automatic field generation +- **``** - Confirmation dialogs for destructive actions + +Example: +```tsx +import DataGrid from '@/components/admin/DataGrid'; + + handleEdit(row)} + onDelete={(row) => handleDelete(row)} +/> +``` + ## Available Scripts ### Development @@ -181,7 +302,33 @@ DATABASE_URL=file:./local.db ## Authentication -This project uses [Clerk](https://clerk.com) for authentication. To set up: +This project includes a **JWT-based admin authentication system** with secure session management: + +- **Admin Login**: Username/password authentication at `/admin/login` +- **Session Management**: JWT tokens stored in HTTP-only cookies +- **Protected Routes**: Admin API endpoints require valid session +- **Secure**: bcrypt password hashing, 24-hour session expiration + +### Admin User Setup + +Create an admin user by running: + +```bash +npm run db:seed-admin +``` + +Or set environment variables for automatic creation on startup: + +```env +CREATE_ADMIN_USER=true +ADMIN_USERNAME=admin +ADMIN_PASSWORD=your_secure_password +JWT_SECRET=your_jwt_secret_here +``` + +### Clerk Integration (Optional) + +The project also supports [Clerk](https://clerk.com) for additional authentication options: 1. Create a Clerk account and application 2. Copy your API keys to `.env.local`: diff --git a/ROADMAP.md b/ROADMAP.md index 0e6e0ca..b67913d 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -2,13 +2,41 @@ This document outlines the planned features, improvements, and technical debt items for the project. Items are organized by priority and implementation timeline. +## Architecture Overview + +๐Ÿ—๏ธ **Configuration-Driven Feature System** + +This project uses a **JSON-driven architecture** that allows features to be defined declaratively and automatically generated: + +- **Feature Configuration** (`src/config/features.json`): Define features, endpoints, UI elements, and data types in JSON +- **Automatic UI Generation**: Navigation items and components are generated by looping over the configuration +- **Reusable Components**: Shared components (`DataGrid`, `FormDialog`, `ConfirmDialog`) are used across all features +- **Easy Feature Management**: Enable/disable features by changing a single flag in the JSON +- **Type-Safe**: TypeScript interfaces ensure type safety across the configuration + +**Benefits:** +- Add new features by updating JSON configuration +- Consistent UI patterns across all features +- Reduced code duplication +- Easy maintenance and scalability +- Feature flags for controlled rollouts + +See `src/config/features.json` for the complete feature configuration. + ## Current Status โœ… **Completed** - Next.js 16 with App Router - PostgreSQL 15 integration (included as default in Docker) - DrizzleORM for database operations (supports PostgreSQL, MySQL, SQLite) +- **Configuration-driven feature system with JSON** +- **Reusable admin UI components (DataGrid, FormDialog, ConfirmDialog)** +- **Database CRUD operations API (Create, Read, Update, Delete)** +- **Table schema inspection API** +- **Table management API (Create, Drop tables)** +- **Column management API (Add, Modify, Delete columns)** - Basic authentication system (Clerk integration available) +- **Admin authentication with JWT and session management** - Docker containerization with optional embedded PostgreSQL - Unit testing with Vitest - E2E testing with Playwright @@ -23,17 +51,21 @@ This document outlines the planned features, improvements, and technical debt it ### High Priority -- [ ] **Database CRUD Operations** - - Create schema management interface - - Implement table creation/editing UI - - Add column type management (add, modify, delete columns) - - Implement record CRUD operations (Create, Read, Update, Delete) - - Add data validation and constraints management - - Build query builder interface - - Add foreign key relationship management - - Implement index management UI - - Add table migration history viewer - - Create database backup/restore UI +- [x] **Database CRUD Operations** โœ… **IMPLEMENTED** + - [x] โœ… Implement record CRUD operations (Create, Read, Update, Delete via API) + - [x] โœ… Build reusable DataGrid component with edit/delete actions + - [x] โœ… Create FormDialog component for create/edit operations + - [x] โœ… Add ConfirmDialog component for delete confirmations + - [x] โœ… Implement table schema inspection API + - [ ] Create schema management interface + - [ ] Implement table creation/editing UI (API ready, UI pending) + - [ ] Add column type management UI (API ready, UI pending) + - [ ] Add data validation and constraints management + - [ ] Build query builder interface + - [ ] Add foreign key relationship management + - [ ] Implement index management UI + - [ ] Add table migration history viewer + - [ ] Create database backup/restore UI - [ ] **Multi-Database Server Support** ๐Ÿ”Œ - **Connection Management** diff --git a/src/app/admin/dashboard/page.tsx.backup b/src/app/admin/dashboard/page.tsx.backup new file mode 100644 index 0000000..275d9ea --- /dev/null +++ b/src/app/admin/dashboard/page.tsx.backup @@ -0,0 +1,369 @@ +'use client'; + +import AddIcon from '@mui/icons-material/Add'; +import CodeIcon from '@mui/icons-material/Code'; +import DeleteIcon from '@mui/icons-material/Delete'; +import EditIcon from '@mui/icons-material/Edit'; +import LogoutIcon from '@mui/icons-material/Logout'; +import StorageIcon from '@mui/icons-material/Storage'; +import TableChartIcon from '@mui/icons-material/TableChart'; +import { + Alert, + AppBar, + Box, + Button, + CircularProgress, + Dialog, + DialogActions, + DialogContent, + DialogTitle, + Drawer, + IconButton, + List, + ListItem, + ListItemButton, + ListItemIcon, + ListItemText, + Paper, + Table, + TableBody, + TableCell, + TableContainer, + TableHead, + TableRow, + TextField, + Toolbar, + Typography, +} from '@mui/material'; +import { ThemeProvider } from '@mui/material/styles'; +import { useRouter } from 'next/navigation'; +import { useCallback, useEffect, useState } from 'react'; +import { theme } from '@/utils/theme'; + +const DRAWER_WIDTH = 240; + +type TabPanelProps = { + children?: React.ReactNode; + index: number; + value: number; +}; + +function TabPanel(props: TabPanelProps) { + const { children, value, index, ...other } = props; + + return ( + + ); +} + +export default function AdminDashboard() { + const router = useRouter(); + const [tabValue, setTabValue] = useState(0); + const [tables, setTables] = useState([]); + const [selectedTable, setSelectedTable] = useState(''); + const [queryText, setQueryText] = useState(''); + const [queryResult, setQueryResult] = useState(null); + const [tableSchema, setTableSchema] = useState(null); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(''); + const [successMessage, setSuccessMessage] = useState(''); + + // Dialog states + const [openCreateDialog, setOpenCreateDialog] = useState(false); + const [openEditDialog, setOpenEditDialog] = useState(false); + const [openDeleteDialog, setOpenDeleteDialog] = useState(false); + const [editingRecord, setEditingRecord] = useState(null); + const [deletingRecord, setDeletingRecord] = useState(null); + const [formData, setFormData] = useState({}); + + const fetchTables = useCallback(async () => { + try { + const response = await fetch('/api/admin/tables'); + if (!response.ok) { + if (response.status === 401) { + router.push('/admin/login'); + return; + } + throw new Error('Failed to fetch tables'); + } + const data = await response.json(); + setTables(data.tables); + } catch (err: any) { + setError(err.message); + } + }, [router]); + + useEffect(() => { + fetchTables(); + }, [fetchTables]); + + const handleTableClick = async (tableName: string) => { + setSelectedTable(tableName); + setLoading(true); + setError(''); + setSuccessMessage(''); + setQueryResult(null); + + try { + // Fetch table data + const dataResponse = await fetch('/api/admin/table-data', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ tableName }), + }); + + if (!response.ok) { + const data = await dataResponse.json(); + throw new Error(data.error || 'Query failed'); + } + + const data = await dataResponse.json(); + setQueryResult(data); + + // Fetch table schema + const schemaResponse = await fetch('/api/admin/table-schema', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ tableName }), + }); + + if (schemaResponse.ok) { + const schemaData = await schemaResponse.json(); + setTableSchema(schemaData); + } + } catch (err: any) { + setError(err.message); + } finally { + setLoading(false); + } + }; + + const handleQuerySubmit = async () => { + if (!queryText.trim()) { + setError('Please enter a query'); + return; + } + + setLoading(true); + setError(''); + setQueryResult(null); + + try { + const response = await fetch('/api/admin/query', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ query: queryText }), + }); + + const data = await response.json(); + + if (!response.ok) { + throw new Error(data.error || 'Query failed'); + } + + setQueryResult(data); + } catch (err: any) { + setError(err.message); + } finally { + setLoading(false); + } + }; + + const handleLogout = async () => { + try { + await fetch('/api/admin/logout', { + method: 'POST', + }); + router.push('/admin/login'); + router.refresh(); + } catch (err) { + console.error('Logout error:', err); + } + }; + + return ( + + + theme.zIndex.drawer + 1 }} + > + + + + Postgres Admin Panel + + + + + + + + + + + setTabValue(0)}> + + + + + + + + setTabValue(1)}> + + + + + + + + + + + + + + + + Database Tables + + + + + {tables.map(table => ( + + handleTableClick(table.table_name)}> + + + + + + + ))} + + + + {selectedTable && ( + + Table: + {' '} + {selectedTable} + + )} + + + + + SQL Query Interface + + + + setQueryText(e.target.value)} + placeholder="SELECT * FROM your_table LIMIT 10;" + sx={{ mb: 2 }} + /> + + + + + {error && ( + + {error} + + )} + + {loading && ( + + + + )} + + {queryResult && !loading && ( + + + + Rows returned: + {' '} + {queryResult.rowCount} + + + + + + + {queryResult.fields?.map((field: any) => ( + + {field.name} + + ))} + + + + {queryResult.rows?.map((row: any, idx: number) => ( + + {queryResult.fields?.map((field: any) => ( + + {row[field.name] !== null + ? String(row[field.name]) + : 'NULL'} + + ))} + + ))} + +
+
+
+ )} +
+
+
+ ); +}