diff --git a/AUDIT_LOGGING_IMPLEMENTATION.md b/AUDIT_LOGGING_IMPLEMENTATION.md deleted file mode 100644 index e86f219..0000000 --- a/AUDIT_LOGGING_IMPLEMENTATION.md +++ /dev/null @@ -1,379 +0,0 @@ -# Audit Logging Implementation - -This document describes the audit logging system implemented for the panel application. The system provides comprehensive tracking of user actions and system events for security, compliance, and monitoring purposes. - -## Features - -- **Comprehensive Action Tracking**: Logs all CRUD operations on projects, tasks, contracts, notes, and user management -- **Authentication Events**: Tracks login attempts, successes, and failures -- **Detailed Context**: Captures IP addresses, user agents, and request details -- **Flexible Filtering**: Query logs by user, action, resource type, date range, and more -- **Statistics Dashboard**: Provides insights into system usage patterns -- **Role-based Access**: Only admins and project managers can view audit logs -- **Performance Optimized**: Uses database indexes for efficient querying - -## Architecture - -### Core Components - -1. **Audit Log Utility** (`src/lib/auditLog.js`) - - - Core logging functions - - Query and statistics functions - - Action and resource type constants - -2. **API Endpoints** (`src/app/api/audit-logs/`) - - - `/api/audit-logs` - Query audit logs with filtering - - `/api/audit-logs/stats` - Get audit log statistics - -3. **UI Components** (`src/components/AuditLogViewer.js`) - - - Interactive audit log viewer - - Advanced filtering interface - - Statistics dashboard - -4. **Admin Pages** (`src/app/admin/audit-logs/`) - - Admin interface for viewing audit logs - - Role-based access control - -### Database Schema - -The audit logs are stored in the `audit_logs` table: - -```sql -CREATE TABLE audit_logs ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - user_id TEXT, -- User who performed the action - action TEXT NOT NULL, -- Action performed (see AUDIT_ACTIONS) - resource_type TEXT, -- Type of resource affected - resource_id TEXT, -- ID of the affected resource - ip_address TEXT, -- IP address of the user - user_agent TEXT, -- Browser/client information - timestamp TEXT DEFAULT CURRENT_TIMESTAMP, - details TEXT, -- Additional details (JSON) - FOREIGN KEY (user_id) REFERENCES users(id) -); -``` - -## Usage - -### Basic Logging - -```javascript -import { logAuditEvent, AUDIT_ACTIONS, RESOURCE_TYPES } from "@/lib/auditLog"; - -// Log a simple action -logAuditEvent({ - action: AUDIT_ACTIONS.PROJECT_CREATE, - userId: "user123", - resourceType: RESOURCE_TYPES.PROJECT, - resourceId: "proj-456", - ipAddress: req.ip, - userAgent: req.headers["user-agent"], - details: { - project_name: "New Project", - project_number: "NP-001", - }, -}); -``` - -### API Route Integration - -```javascript -import { logApiAction, AUDIT_ACTIONS, RESOURCE_TYPES } from "@/lib/auditLog"; - -export async function POST(req) { - const data = await req.json(); - - // Perform the operation - const result = createProject(data); - - // Log the action - logApiAction( - req, - AUDIT_ACTIONS.PROJECT_CREATE, - RESOURCE_TYPES.PROJECT, - result.id.toString(), - req.session, - { projectData: data } - ); - - return NextResponse.json({ success: true, id: result.id }); -} -``` - -### Querying Audit Logs - -```javascript -import { getAuditLogs, getAuditLogStats } from "@/lib/auditLog"; - -// Get recent logs -const recentLogs = getAuditLogs({ - limit: 50, - orderBy: "timestamp", - orderDirection: "DESC", -}); - -// Get logs for a specific user -const userLogs = getAuditLogs({ - userId: "user123", - startDate: "2025-01-01T00:00:00Z", - endDate: "2025-12-31T23:59:59Z", -}); - -// Get statistics -const stats = getAuditLogStats({ - startDate: "2025-01-01T00:00:00Z", - endDate: "2025-12-31T23:59:59Z", -}); -``` - -## Available Actions - -### Authentication Actions - -- `login` - Successful user login -- `logout` - User logout -- `login_failed` - Failed login attempt - -### Project Actions - -- `project_create` - Project creation -- `project_update` - Project modification -- `project_delete` - Project deletion -- `project_view` - Project viewing - -### Task Actions - -- `task_create` - Task creation -- `task_update` - Task modification -- `task_delete` - Task deletion -- `task_status_change` - Task status modification - -### Project Task Actions - -- `project_task_create` - Project task assignment -- `project_task_update` - Project task modification -- `project_task_delete` - Project task removal -- `project_task_status_change` - Project task status change - -### Contract Actions - -- `contract_create` - Contract creation -- `contract_update` - Contract modification -- `contract_delete` - Contract deletion - -### Note Actions - -- `note_create` - Note creation -- `note_update` - Note modification -- `note_delete` - Note deletion - -### Admin Actions - -- `user_create` - User account creation -- `user_update` - User account modification -- `user_delete` - User account deletion -- `user_role_change` - User role modification - -### System Actions - -- `data_export` - Data export operations -- `bulk_operation` - Bulk data operations - -## Resource Types - -- `project` - Project resources -- `task` - Task templates -- `project_task` - Project-specific tasks -- `contract` - Contracts -- `note` - Notes and comments -- `user` - User accounts -- `session` - Authentication sessions -- `system` - System-level operations - -## API Endpoints - -### GET /api/audit-logs - -Query audit logs with optional filtering. - -**Query Parameters:** - -- `userId` - Filter by user ID -- `action` - Filter by action type -- `resourceType` - Filter by resource type -- `resourceId` - Filter by resource ID -- `startDate` - Filter from date (ISO string) -- `endDate` - Filter to date (ISO string) -- `limit` - Maximum results (default: 100) -- `offset` - Results offset (default: 0) -- `orderBy` - Order by field (default: timestamp) -- `orderDirection` - ASC or DESC (default: DESC) -- `includeStats` - Include statistics (true/false) - -**Response:** - -```json -{ - "success": true, - "data": [ - { - "id": 1, - "user_id": "user123", - "user_name": "John Doe", - "user_email": "john@example.com", - "action": "project_create", - "resource_type": "project", - "resource_id": "proj-456", - "ip_address": "192.168.1.100", - "user_agent": "Mozilla/5.0...", - "timestamp": "2025-07-09T10:30:00Z", - "details": { - "project_name": "New Project", - "project_number": "NP-001" - } - } - ], - "stats": { - "total": 150, - "actionBreakdown": [...], - "userBreakdown": [...], - "resourceBreakdown": [...] - } -} -``` - -### GET /api/audit-logs/stats - -Get audit log statistics. - -**Query Parameters:** - -- `startDate` - Filter from date (ISO string) -- `endDate` - Filter to date (ISO string) - -**Response:** - -```json -{ - "success": true, - "data": { - "total": 150, - "actionBreakdown": [ - { "action": "project_view", "count": 45 }, - { "action": "login", "count": 23 } - ], - "userBreakdown": [ - { "user_id": "user123", "user_name": "John Doe", "count": 67 } - ], - "resourceBreakdown": [{ "resource_type": "project", "count": 89 }] - } -} -``` - -## Access Control - -Audit logs are restricted to users with the following roles: - -- `admin` - Full access to all audit logs -- `project_manager` - Full access to all audit logs - -Other users cannot access audit logs. - -## Testing - -Run the audit logging test script: - -```bash -node test-audit-logging.mjs -``` - -This will: - -1. Create sample audit events -2. Test querying and filtering -3. Verify statistics generation -4. Test date range filtering - -## Integration Status - -The audit logging system has been integrated into the following API routes: - -โœ… **Authentication** (`src/lib/auth.js`) - -- Login success/failure tracking -- Account lockout logging - -โœ… **Projects** (`src/app/api/projects/`) - -- Project CRUD operations -- List view access - -โœ… **Notes** (`src/app/api/notes/`) - -- Note creation, updates, and deletion - -๐Ÿ”„ **Pending Integration:** - -- Tasks API -- Project Tasks API -- Contracts API -- User management API - -## Performance Considerations - -- Database indexes are created on frequently queried fields -- Large result sets are paginated -- Statistics queries are optimized for common use cases -- Failed operations are logged to prevent data loss - -## Security Features - -- IP address tracking for forensic analysis -- User agent logging for client identification -- Failed authentication attempt tracking -- Detailed change logging for sensitive operations -- Role-based access control for audit log viewing - -## Maintenance - -### Log Retention - -Consider implementing log retention policies: - -```sql --- Delete audit logs older than 1 year -DELETE FROM audit_logs -WHERE timestamp < datetime('now', '-1 year'); -``` - -### Monitoring - -Monitor audit log growth and performance: - -```sql --- Check audit log table size -SELECT COUNT(*) as total_logs, - MIN(timestamp) as oldest_log, - MAX(timestamp) as newest_log -FROM audit_logs; - --- Check most active users -SELECT user_id, COUNT(*) as activity_count -FROM audit_logs -WHERE timestamp > datetime('now', '-30 days') -GROUP BY user_id -ORDER BY activity_count DESC -LIMIT 10; -``` - -## Future Enhancements - -- Real-time audit log streaming -- Advanced analytics and reporting -- Integration with external SIEM systems -- Automatic anomaly detection -- Compliance reporting templates -- Log export functionality diff --git a/AUTHORIZATION_IMPLEMENTATION.md b/AUTHORIZATION_IMPLEMENTATION.md deleted file mode 100644 index 7607ecf..0000000 --- a/AUTHORIZATION_IMPLEMENTATION.md +++ /dev/null @@ -1,971 +0,0 @@ -# Authorization Implementation Guide - -## Project Overview - -This document outlines the implementation strategy for adding authentication and authorization to the Project Management Panel - a Next.js 15 application with SQLite database. - -## Current State Analysis (Updated: June 25, 2025) - -### โœ… What We Have Implemented - -- **Framework**: Next.js 15 with App Router -- **Database**: SQLite with better-sqlite3 -- **Authentication**: NextAuth.js v5 with credentials provider -- **User Management**: Complete user CRUD operations with bcrypt password hashing -- **Database Schema**: Users table with roles, audit logs, sessions -- **API Protection**: Middleware system with role-based access control -- **Session Management**: JWT-based sessions with 30-day expiration -- **Security Features**: Account lockout, failed login tracking, password validation -- **UI Components**: Authentication provider, navigation with user context -- **Auth Pages**: Sign-in page implemented - -### โœ… What's Protected - -- **API Routes**: All major endpoints (projects, contracts, tasks, notes) are protected -- **Role Hierarchy**: admin > project_manager > user > read_only -- **Navigation**: Role-based menu items (admin sees user management) -- **Session Security**: Automatic session management and validation - -### ๐Ÿ”„ Partially Implemented - -- **Auth Pages**: Sign-in exists, missing sign-out and error pages -- **User Interface**: Basic auth integration, could use more polish -- **Admin Features**: User management backend exists, UI needs completion -- **Audit Logging**: Database schema exists, not fully integrated - -### โŒ Still Missing - -- Complete user management UI for admins -- Password reset functionality -- Rate limiting implementation -- Enhanced input validation schemas -- CSRF protection -- Security headers middleware -- Comprehensive error handling -- Email notifications - -## Recommended Implementation Strategy - -### 1. Authentication Solution: NextAuth.js - -**Why NextAuth.js?** - -- โœ… Native Next.js 15 App Router support -- โœ… Database session management -- โœ… Built-in security features (CSRF, JWT handling) -- โœ… Flexible provider system -- โœ… SQLite adapter available - -### 2. Role-Based Access Control (RBAC) - -**Proposed User Roles:** - -| Role | Permissions | Use Case | -| ------------------- | --------------------------------------- | ----------------------- | -| **Admin** | Full system access, user management | System administrators | -| **Project Manager** | Manage all projects/tasks, view reports | Team leads, supervisors | -| **User** | View/edit assigned projects/tasks | Regular employees | -| **Read-only** | View-only access to data | Clients, stakeholders | - -## Implementation Status - -### โœ… Phase 1: Foundation Setup - COMPLETED - -#### 1.1 Dependencies - โœ… INSTALLED - -- NextAuth.js v5 (beta) -- bcryptjs for password hashing -- Zod for validation -- Better-sqlite3 adapter compatibility - -#### 1.2 Environment Configuration - โœ… COMPLETED - -- `.env.local` configured with NEXTAUTH_SECRET and NEXTAUTH_URL -- Database URL configuration -- Development environment setup - -#### 1.3 Database Schema - โœ… IMPLEMENTED - -- Users table with roles and security features -- Sessions table for NextAuth.js -- Audit logs table for security tracking -- Proper indexes for performance - -#### 1.4 Initial Admin User - โœ… COMPLETED - -- `scripts/create-admin.js` script available -- Default admin user: admin@localhost.com / admin123456 - -### โœ… Phase 2: Authentication Core - COMPLETED - -#### 2.1 NextAuth.js Configuration - โœ… IMPLEMENTED - -- **File**: `src/lib/auth.js` -- Credentials provider with email/password -- JWT session strategy with 30-day expiration -- Account lockout after 5 failed attempts (15-minute lockout) -- Password verification with bcrypt -- Failed login attempt tracking -- Session callbacks for role management - -#### 2.2 API Route Handlers - โœ… IMPLEMENTED - -- **File**: `src/app/api/auth/[...nextauth]/route.js` -- NextAuth.js handlers properly configured - -#### 2.3 User Management System - โœ… IMPLEMENTED - -- **File**: `src/lib/userManagement.js` -- Complete CRUD operations for users -- Password hashing and validation -- Role management functions -- User lookup by ID and email - -### โœ… Phase 3: Authorization Middleware - COMPLETED - -#### 3.1 API Protection Middleware - โœ… IMPLEMENTED - -- **File**: `src/lib/middleware/auth.js` -- `withAuth()` function for protecting routes -- Role hierarchy enforcement (admin=4, project_manager=3, user=2, read_only=1) -- Helper functions: `withReadAuth`, `withUserAuth`, `withAdminAuth`, `withManagerAuth` -- Proper error handling and status codes - -#### 3.2 Protected API Routes - โœ… IMPLEMENTED - -Example in `src/app/api/projects/route.js`: - -- GET requests require read_only access -- POST requests require user access -- All major API endpoints are protected - -#### 3.3 Session Provider - โœ… IMPLEMENTED - -- **File**: `src/components/auth/AuthProvider.js` -- NextAuth SessionProvider wrapper -- Integrated into root layout - -### ๐Ÿ”„ Phase 4: User Interface - PARTIALLY COMPLETED - -#### 4.1 Authentication Pages - ๐Ÿ”„ PARTIAL - -- โœ… **Sign-in page**: `src/app/auth/signin/page.js` - Complete with form validation -- โŒ **Sign-out page**: Missing -- ๐Ÿ”„ **Error page**: `src/app/auth/error/page.js` - Basic implementation -- โŒ **Unauthorized page**: Missing - -#### 4.2 Navigation Updates - โœ… COMPLETED - -- **File**: `src/components/ui/Navigation.js` -- User session integration with useSession -- Role-based menu items (admin sees user management) -- Sign-out functionality -- Conditional rendering based on auth status - -#### 4.3 User Management Interface - โŒ MISSING - -- Backend exists in userManagement.js -- Admin UI for user CRUD operations needed -- Role assignment interface needed - -### โŒ Phase 5: Security Enhancements - NOT STARTED - -#### 5.1 Input Validation Schemas - โŒ MISSING - -- Zod schemas for API endpoints -- Request validation middleware - -#### 5.2 Rate Limiting - โŒ MISSING - -- Rate limiting middleware -- IP-based request tracking - -#### 5.3 Security Headers - โŒ MISSING - -- CSRF protection -- Security headers middleware -- Content Security Policy - -```javascript -import NextAuth from "next-auth"; -import CredentialsProvider from "next-auth/providers/credentials"; -import { BetterSQLite3Adapter } from "@auth/better-sqlite3-adapter"; -import db from "./db.js"; -import bcrypt from "bcryptjs"; -import { z } from "zod"; - -const loginSchema = z.object({ - email: z.string().email("Invalid email format"), - password: z.string().min(6, "Password must be at least 6 characters"), -}); - -export const { handlers, auth, signIn, signOut } = NextAuth({ - adapter: BetterSQLite3Adapter(db), - session: { - strategy: "database", - maxAge: 30 * 24 * 60 * 60, // 30 days - updateAge: 24 * 60 * 60, // 24 hours - }, - providers: [ - CredentialsProvider({ - name: "credentials", - credentials: { - email: { label: "Email", type: "email" }, - password: { label: "Password", type: "password" }, - }, - async authorize(credentials, req) { - try { - // Validate input - const validatedFields = loginSchema.parse(credentials); - - // Check if user exists and is active - const user = db - .prepare( - ` - SELECT id, email, name, password_hash, role, is_active, - failed_login_attempts, locked_until - FROM users - WHERE email = ? AND is_active = 1 - ` - ) - .get(validatedFields.email); - - if (!user) { - throw new Error("Invalid credentials"); - } - - // Check if account is locked - if (user.locked_until && new Date(user.locked_until) > new Date()) { - throw new Error("Account temporarily locked"); - } - - // Verify password - const isValidPassword = await bcrypt.compare( - validatedFields.password, - user.password_hash - ); - - if (!isValidPassword) { - // Increment failed attempts - db.prepare( - ` - UPDATE users - SET failed_login_attempts = failed_login_attempts + 1, - locked_until = CASE - WHEN failed_login_attempts >= 4 - THEN datetime('now', '+15 minutes') - ELSE locked_until - END - WHERE id = ? - ` - ).run(user.id); - - throw new Error("Invalid credentials"); - } - - // Reset failed attempts and update last login - db.prepare( - ` - UPDATE users - SET failed_login_attempts = 0, - locked_until = NULL, - last_login = CURRENT_TIMESTAMP - WHERE id = ? - ` - ).run(user.id); - - // Log successful login - logAuditEvent(user.id, "LOGIN_SUCCESS", "user", user.id, req); - - return { - id: user.id, - email: user.email, - name: user.name, - role: user.role, - }; - } catch (error) { - console.error("Login error:", error); - return null; - } - }, - }), - ], - callbacks: { - async jwt({ token, user, account }) { - if (user) { - token.role = user.role; - token.userId = user.id; - } - return token; - }, - async session({ session, token, user }) { - if (token) { - session.user.id = token.userId || token.sub; - session.user.role = token.role || user?.role; - } - return session; - }, - async signIn({ user, account, profile, email, credentials }) { - // Additional sign-in logic if needed - return true; - }, - }, - pages: { - signIn: "/auth/signin", - signOut: "/auth/signout", - error: "/auth/error", - }, - events: { - async signOut({ session, token }) { - if (session?.user?.id) { - logAuditEvent(session.user.id, "LOGOUT", "user", session.user.id); - } - }, - }, -}); - -// Audit logging helper -function logAuditEvent(userId, action, resourceType, resourceId, req = null) { - try { - db.prepare( - ` - INSERT INTO audit_logs (user_id, action, resource_type, resource_id, ip_address, user_agent) - VALUES (?, ?, ?, ?, ?, ?) - ` - ).run( - userId, - action, - resourceType, - resourceId, - req?.ip || "unknown", - req?.headers?.["user-agent"] || "unknown" - ); - } catch (error) { - console.error("Audit log error:", error); - } -} -``` - -#### 2.2 API Route Handlers - -Create `src/app/api/auth/[...nextauth]/route.js`: - -```javascript -import { handlers } from "@/lib/auth"; - -export const { GET, POST } = handlers; -``` - -### Phase 3: Authorization Middleware - -#### 3.1 API Protection Middleware - -Create `src/lib/middleware/auth.js`: - -```javascript -import { auth } from "@/lib/auth"; -import { NextResponse } from "next/server"; -import { z } from "zod"; - -// Role hierarchy for permission checking -const ROLE_HIERARCHY = { - admin: 4, - project_manager: 3, - user: 2, - read_only: 1, -}; - -export function withAuth(handler, options = {}) { - return async (req, context) => { - try { - const session = await auth(); - - // Check if user is authenticated - if (!session?.user) { - return NextResponse.json( - { error: "Authentication required" }, - { status: 401 } - ); - } - - // Check if user account is active - const user = db - .prepare("SELECT is_active FROM users WHERE id = ?") - .get(session.user.id); - if (!user?.is_active) { - return NextResponse.json( - { error: "Account deactivated" }, - { status: 403 } - ); - } - - // Check role-based permissions - if ( - options.requiredRole && - !hasPermission(session.user.role, options.requiredRole) - ) { - logAuditEvent( - session.user.id, - "ACCESS_DENIED", - options.resource || "api", - req.url - ); - return NextResponse.json( - { error: "Insufficient permissions" }, - { status: 403 } - ); - } - - // Check resource-specific permissions - if (options.checkResourceAccess) { - const hasAccess = await options.checkResourceAccess( - session.user, - context.params - ); - if (!hasAccess) { - return NextResponse.json( - { error: "Access denied to this resource" }, - { status: 403 } - ); - } - } - - // Validate request body if schema provided - if ( - options.bodySchema && - (req.method === "POST" || - req.method === "PUT" || - req.method === "PATCH") - ) { - try { - const body = await req.json(); - options.bodySchema.parse(body); - } catch (error) { - return NextResponse.json( - { error: "Invalid request data", details: error.errors }, - { status: 400 } - ); - } - } - - // Add user info to request - req.user = session.user; - req.session = session; - - // Call the original handler - return await handler(req, context); - } catch (error) { - console.error("Auth middleware error:", error); - return NextResponse.json( - { error: "Internal server error" }, - { status: 500 } - ); - } - }; -} - -export function hasPermission(userRole, requiredRole) { - return ROLE_HIERARCHY[userRole] >= ROLE_HIERARCHY[requiredRole]; -} - -// Helper for read-only operations -export function withReadAuth(handler) { - return withAuth(handler, { requiredRole: "read_only" }); -} - -// Helper for user-level operations -export function withUserAuth(handler) { - return withAuth(handler, { requiredRole: "user" }); -} - -// Helper for project manager operations -export function withManagerAuth(handler) { - return withAuth(handler, { requiredRole: "project_manager" }); -} - -// Helper for admin operations -export function withAdminAuth(handler) { - return withAuth(handler, { requiredRole: "admin" }); -} -``` - -#### 3.2 Client-Side Route Protection - -Create `src/components/auth/ProtectedRoute.js`: - -```javascript -"use client"; - -import { useSession } from "next-auth/react"; -import { useRouter } from "next/navigation"; -import { useEffect } from "react"; - -export function ProtectedRoute({ - children, - requiredRole = null, - fallback = null, -}) { - const { data: session, status } = useSession(); - const router = useRouter(); - - useEffect(() => { - if (status === "loading") return; // Still loading - - if (!session) { - router.push("/auth/signin"); - return; - } - - if (requiredRole && !hasPermission(session.user.role, requiredRole)) { - router.push("/unauthorized"); - return; - } - }, [session, status, router, requiredRole]); - - if (status === "loading") { - return ( -
Loading...
- ); - } - - if (!session) { - return fallback ||
Redirecting to login...
; - } - - if (requiredRole && !hasPermission(session.user.role, requiredRole)) { - return fallback ||
Access denied
; - } - - return children; -} - -function hasPermission(userRole, requiredRole) { - const roleHierarchy = { - admin: 4, - project_manager: 3, - user: 2, - read_only: 1, - }; - - return roleHierarchy[userRole] >= roleHierarchy[requiredRole]; -} -``` - -### Phase 4: User Interface Components - -#### 4.1 Authentication Pages - -Pages to create: - -- `src/app/auth/signin/page.js` - Login form -- `src/app/auth/signout/page.js` - Logout confirmation -- `src/app/auth/error/page.js` - Error handling -- `src/app/unauthorized/page.js` - Access denied page - -#### 4.2 Navigation Updates - -Update `src/components/ui/Navigation.js` to include: - -- Login/logout buttons -- User info display -- Role-based menu items - -#### 4.3 User Management Interface - -For admin users: - -- User listing and management -- Role assignment -- Account activation/deactivation - -### Phase 5: Security Enhancements - -#### 5.1 Input Validation Schemas - -Create `src/lib/schemas/` with Zod schemas for all API endpoints: - -```javascript -// src/lib/schemas/project.js -import { z } from "zod"; - -export const createProjectSchema = z.object({ - contract_id: z.number().int().positive(), - project_name: z.string().min(1).max(255), - project_number: z.string().min(1).max(50), - address: z.string().optional(), - // ... other fields -}); - -export const updateProjectSchema = createProjectSchema.partial(); -``` - -#### 5.2 Rate Limiting - -Implement rate limiting for sensitive endpoints: - -```javascript -// src/lib/middleware/rateLimit.js -const attempts = new Map(); - -export function withRateLimit( - handler, - options = { maxAttempts: 5, windowMs: 15 * 60 * 1000 } -) { - return async (req, context) => { - const key = req.ip || "unknown"; - const now = Date.now(); - const window = attempts.get(key) || { - count: 0, - resetTime: now + options.windowMs, - }; - - if (now > window.resetTime) { - window.count = 1; - window.resetTime = now + options.windowMs; - } else { - window.count++; - } - - attempts.set(key, window); - - if (window.count > options.maxAttempts) { - return NextResponse.json({ error: "Too many requests" }, { status: 429 }); - } - - return handler(req, context); - }; -} -``` - -## Implementation Checklist (Updated Status) - -### โœ… Phase 1: Foundation - COMPLETED - -- [x] Install dependencies (NextAuth.js v5, bcryptjs, zod) -- [x] Create environment configuration (.env.local) -- [x] Extend database schema (users, sessions, audit_logs) -- [x] Create initial admin user script - -### โœ… Phase 2: Authentication - COMPLETED - -- [x] Configure NextAuth.js with credentials provider -- [x] Create API route handlers (/api/auth/[...nextauth]) -- [x] Implement user management system -- [x] Test login/logout functionality - -### โœ… Phase 3: Authorization - COMPLETED - -- [x] Implement API middleware (withAuth, role hierarchy) -- [x] Protect existing API routes (projects, contracts, tasks, notes) -- [x] Create role-based helper functions -- [x] Integrate session provider in app layout - -### ๐Ÿ”„ Phase 4: User Interface - IN PROGRESS - -- [x] Create sign-in page with form validation -- [x] Update navigation component with auth integration -- [x] Add role-based menu items -- [ ] Create sign-out confirmation page -- [ ] Create error handling page -- [ ] Create unauthorized access page -- [ ] Build admin user management interface - -### โŒ Phase 5: Security Enhancements - NOT STARTED - -- [ ] Add input validation schemas to all endpoints -- [ ] Implement rate limiting for sensitive operations -- [ ] Add comprehensive audit logging -- [ ] Create security headers middleware -- [ ] Implement CSRF protection -- [ ] Add password reset functionality - -## Current Working Features - -### ๐Ÿ” Authentication System - -- **Login/Logout**: Fully functional with NextAuth.js -- **Session Management**: JWT-based with 30-day expiration -- **Password Security**: bcrypt hashing with salt rounds -- **Account Lockout**: 5 failed attempts = 15-minute lockout -- **Role System**: 4-tier hierarchy (admin, project_manager, user, read_only) - -### ๐Ÿ›ก๏ธ Authorization System - -- **API Protection**: All major endpoints require authentication -- **Role-Based Access**: Different permission levels per endpoint -- **Middleware**: Clean abstraction with helper functions -- **Session Validation**: Automatic session verification - -### ๐Ÿ“ฑ User Interface - -- **Navigation**: Context-aware with user info and sign-out -- **Auth Pages**: Professional sign-in form with error handling -- **Role Integration**: Admin users see additional menu items -- **Responsive**: Works across device sizes - -### ๐Ÿ—„๏ธ Database Security - -- **User Management**: Complete CRUD with proper validation -- **Audit Schema**: Ready for comprehensive logging -- **Indexes**: Optimized for performance -- **Constraints**: Role validation and data integrity - -## Next Priority Tasks - -1. **Complete Auth UI** (High Priority) - - - Sign-out confirmation page - - Unauthorized access page - - Enhanced error handling - -2. **Admin User Management** (High Priority) - - - User listing interface - - Create/edit user forms - - Role assignment controls - -3. **Security Enhancements** (Medium Priority) - - - Input validation schemas - - Rate limiting middleware - - Comprehensive audit logging - -4. **Password Management** (Medium Priority) - - Password reset functionality - - Password strength requirements - - Password change interface - -## User Tracking in Projects - NEW FEATURE โœ… - -### ๐Ÿ“Š Project User Management Implementation - -We've successfully implemented comprehensive user tracking for projects: - -#### Database Schema Updates โœ… - -- **created_by**: Tracks who created the project (user ID) -- **assigned_to**: Tracks who is assigned to work on the project (user ID) -- **created_at**: Timestamp when project was created -- **updated_at**: Timestamp when project was last modified -- **Indexes**: Performance optimized with proper foreign key indexes - -#### API Enhancements โœ… - -- **Enhanced Queries**: Projects now include user names and emails via JOIN operations -- **User Assignment**: New `/api/projects/users` endpoint for user management -- **Query Filters**: Support for filtering projects by assigned user or creator -- **User Context**: Create/update operations automatically capture authenticated user ID - -#### UI Components โœ… - -- **Project Form**: User assignment dropdown in create/edit forms -- **Project Listing**: "Created By" and "Assigned To" columns in project table -- **User Selection**: Dropdown populated with active users for assignment - -#### New Query Functions โœ… - -- `getAllUsersForAssignment()`: Get active users for assignment dropdown -- `getProjectsByAssignedUser(userId)`: Filter projects by assignee -- `getProjectsByCreator(userId)`: Filter projects by creator -- `updateProjectAssignment(projectId, userId)`: Update project assignment - -#### Security Integration โœ… - -- **Authentication Required**: All user operations require valid session -- **Role-Based Access**: User assignment respects role hierarchy -- **Audit Ready**: Infrastructure prepared for comprehensive user action logging - -### Usage Examples - -#### Creating Projects with User Tracking - -```javascript -// Projects are automatically assigned to the authenticated user as creator -POST /api/projects -{ - "project_name": "New Project", - "assigned_to": "user-id-here", // Optional assignment - // ... other project data -} -``` - -#### Filtering Projects by User - -```javascript -// Get projects assigned to specific user -GET /api/projects?assigned_to=user-id - -// Get projects created by specific user -GET /api/projects?created_by=user-id -``` - -#### Updating Project Assignment - -```javascript -POST /api/projects/users -{ - "projectId": 123, - "assignedToUserId": "new-user-id" -} -``` - -## Project Tasks User Tracking - NEW FEATURE โœ… - -### ๐Ÿ“‹ Task User Management Implementation - -We've also implemented comprehensive user tracking for project tasks: - -#### Database Schema Updates โœ… - -- **created_by**: Tracks who created the task (user ID) -- **assigned_to**: Tracks who is assigned to work on the task (user ID) -- **created_at**: Timestamp when task was created -- **updated_at**: Timestamp when task was last modified -- **Indexes**: Performance optimized with proper foreign key indexes - -#### API Enhancements โœ… - -- **Enhanced Queries**: Tasks now include user names and emails via JOIN operations -- **User Assignment**: New `/api/project-tasks/users` endpoint for user management -- **Query Filters**: Support for filtering tasks by assigned user or creator -- **User Context**: Create/update operations automatically capture authenticated user ID - -#### UI Components โœ… - -- **Task Form**: User assignment dropdown in create task forms -- **Task Listing**: "Created By" and "Assigned To" columns in task table -- **User Selection**: Dropdown populated with active users for assignment - -#### New Task Query Functions โœ… - -- `getAllUsersForTaskAssignment()`: Get active users for assignment dropdown -- `getProjectTasksByAssignedUser(userId)`: Filter tasks by assignee -- `getProjectTasksByCreator(userId)`: Filter tasks by creator -- `updateProjectTaskAssignment(taskId, userId)`: Update task assignment - -#### Task Creation Behavior โœ… - -- **Auto-assignment**: Tasks are automatically assigned to the authenticated user as creator -- **Optional Assignment**: Users can assign tasks to other team members during creation -- **Creator Tracking**: All tasks track who created them for accountability - -### Task Usage Examples - -#### Creating Tasks with User Tracking - -```javascript -// Tasks are automatically assigned to the authenticated user as creator -POST /api/project-tasks -{ - "project_id": 123, - "task_template_id": 1, // or custom_task_name for custom tasks - "assigned_to": "user-id-here", // Optional, defaults to creator - "priority": "high" -} -``` - -#### Filtering Tasks by User - -```javascript -// Get tasks assigned to specific user -GET /api/project-tasks?assigned_to=user-id - -// Get tasks created by specific user -GET /api/project-tasks?created_by=user-id -``` - -#### Updating Task Assignment - -```javascript -POST /api/project-tasks/users -{ - "taskId": 456, - "assignedToUserId": "new-user-id" -} -``` - -### Next Enhancements - -1. **Dashboard Views** (Recommended) - - - "My Projects" dashboard showing assigned projects - - Project creation history per user - - Workload distribution reports - -2. **Advanced Filtering** (Future) - - - Multi-user assignment support - - Team-based project assignments - - Role-based project visibility - -3. **Notifications** (Future) - - Email alerts on project assignment - - Deadline reminders for assigned users - - Status change notifications - -## Notes User Tracking - NEW FEATURE โœ… - -### ๐Ÿ“ Notes User Management Implementation - -We've also implemented comprehensive user tracking for all notes (both project notes and task notes): - -#### Database Schema Updates โœ… - -- **created_by**: Tracks who created the note (user ID) -- **is_system**: Distinguishes between user notes and system-generated notes -- **Enhanced queries**: Notes now include user names and emails via JOIN operations -- **Indexes**: Performance optimized with proper indexes for user lookups - -#### API Enhancements โœ… - -- **User Context**: All note creation operations automatically capture authenticated user ID -- **System Notes**: Automatic system notes (task status changes) track who made the change -- **User Information**: Note retrieval includes creator name and email for display - -#### UI Components โœ… - -- **Project Notes**: Display creator name and email in project note listings -- **Task Notes**: Show who added each note with user badges and timestamps -- **System Notes**: Distinguished from user notes with special styling and "System" badge -- **User Attribution**: Clear indication of who created each note and when - -#### New Note Query Functions โœ… - -- `getAllNotesWithUsers()`: Get all notes with user and project/task context -- `getNotesByCreator(userId)`: Filter notes by creator for user activity tracking -- Enhanced `getNotesByProjectId()` and `getNotesByTaskId()` with user information - -#### Automatic User Tracking โœ… - -- **Note Creation**: All new notes automatically record who created them -- **System Notes**: Task status changes generate system notes attributed to the user who made the change -- **Audit Trail**: Complete history of who added what notes and when - -### Notes Usage Examples - -#### Project Notes with User Tracking - -- Notes display creator name in a blue badge next to the timestamp -- Form automatically associates notes with the authenticated user -- Clear visual distinction between different note authors - -#### Task Notes with User Tracking - -- User notes show creator name in a gray badge -- System notes show "System" badge but also track the user who triggered the action -- Full audit trail of task status changes and who made them - -#### System Note Generation - -```javascript -// When a user changes a task status, a system note is automatically created: -// "Status changed from 'pending' to 'in_progress'" - attributed to the user who made the change -``` - -### Benefits - -1. **Accountability**: Full audit trail of who added what notes -2. **Context**: Know who to contact for clarification on specific notes -3. **History**: Track communication and decisions made by team members -4. **System Integration**: Automatic notes for system actions still maintain user attribution -5. **User Experience**: Clear visual indicators of note authors improve team collaboration diff --git a/DEPLOYMENT_TIMEZONE_FIX.md b/DEPLOYMENT_TIMEZONE_FIX.md deleted file mode 100644 index b2ab5ef..0000000 --- a/DEPLOYMENT_TIMEZONE_FIX.md +++ /dev/null @@ -1,129 +0,0 @@ -# Quick Deployment Guide - Timezone Fix - -## For Production Server - -1. **SSH into your server** where Docker is running - -2. **Navigate to project directory** - ```bash - cd /path/to/panel - ``` - -3. **Pull latest code** (includes timezone fixes) - ```bash - git pull origin main - ``` - -4. **Stop running containers** - ```bash - docker-compose -f docker-compose.prod.yml down - ``` - -5. **Rebuild Docker images** (this is critical - it bakes in the timezone configuration) - ```bash - docker-compose -f docker-compose.prod.yml build --no-cache - ``` - -6. **Start containers** - ```bash - docker-compose -f docker-compose.prod.yml up -d - ``` - -7. **Verify timezone is correct** - ```bash - # Check container timezone - docker-compose -f docker-compose.prod.yml exec app date - # Should show Polish time with CEST/CET timezone - - # Example output: - # Sat Oct 4 19:45:00 CEST 2025 - ``` - -8. **Test the fix** - - Post a new note at a known time (e.g., 19:45) - - Verify it displays the same time (19:45) - - Test both project notes and task notes - -## What Changed - -### Code Changes -- โœ… Fixed `datetime('now', 'localtime')` in all database queries -- โœ… Updated display formatters to use Europe/Warsaw timezone -- โœ… Fixed note display in components - -### Docker Changes (Critical!) -- โœ… Set `ENV TZ=Europe/Warsaw` in Dockerfile -- โœ… Configured system timezone in containers -- โœ… Added TZ environment variable to docker-compose files - -## Why Rebuild is Necessary - -The timezone configuration is **baked into the Docker image** during build time: -- `ENV TZ=Europe/Warsaw` - Set during image build -- `RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime` - Executed during image build - -Just restarting containers (`docker-compose restart`) will **NOT** apply these changes! - -## Troubleshooting - -### If times are still wrong after deployment: - -1. **Verify you rebuilt the images** - ```bash - docker images | grep panel - # Check the "CREATED" timestamp - should be recent - ``` - -2. **Check if container has correct timezone** - ```bash - docker-compose -f docker-compose.prod.yml exec app date - ``` - Should show Polish time, not UTC! - -3. **Check SQLite is using correct time** - ```bash - docker-compose -f docker-compose.prod.yml exec app node -e "const db = require('better-sqlite3')('./data/database.sqlite'); console.log(db.prepare(\"SELECT datetime('now', 'localtime') as time\").get());" - ``` - Should show current Polish time - -4. **Force rebuild if needed** - ```bash - docker-compose -f docker-compose.prod.yml down - docker system prune -f - docker-compose -f docker-compose.prod.yml build --no-cache - docker-compose -f docker-compose.prod.yml up -d - ``` - -## Expected Behavior After Fix - -### Before Fix (Docker in UTC): -``` -User posts note at 10:30 Poland time -โ†’ Docker sees 08:30 UTC as "local time" -โ†’ SQLite stores: 08:30 -โ†’ Display shows: 08:30 โŒ (2 hours off!) -``` - -### After Fix (Docker in Europe/Warsaw): -``` -User posts note at 10:30 Poland time -โ†’ Docker sees 10:30 Poland time as "local time" -โ†’ SQLite stores: 10:30 -โ†’ Display shows: 10:30 โœ… (correct!) -``` - -## Important Notes - -1. **Old notes**: Notes created before this fix may still show incorrect times (they were stored in UTC) -2. **New notes**: All new notes after deployment will show correct times -3. **Audit logs**: Continue to work correctly (they always used ISO format) -4. **Zero downtime**: Can't achieve - need to stop/rebuild/start containers - -## Quick Check Command - -After deployment, run this one-liner to verify everything: -```bash -docker-compose -f docker-compose.prod.yml exec app sh -c 'date && node -e "console.log(new Date().toLocaleString(\"pl-PL\"))"' -``` - -Both outputs should show the same Polish time! diff --git a/DOCKER_TIMEZONE_FIX.md b/DOCKER_TIMEZONE_FIX.md deleted file mode 100644 index a77d6d9..0000000 --- a/DOCKER_TIMEZONE_FIX.md +++ /dev/null @@ -1,156 +0,0 @@ -# Docker Timezone Configuration Fix - -## Problem -Even after fixing the SQLite `datetime('now', 'localtime')` calls, notes posted at 10:00 still showed as 08:00 when running in Docker. - -## Root Cause -**Docker containers run in UTC timezone by default!** - -When using `datetime('now', 'localtime')` in SQLite: -- On local Windows machine: Uses Windows timezone (Europe/Warsaw) โ†’ โœ… Correct -- In Docker container: Uses container timezone (UTC) โ†’ โŒ Wrong by 2 hours - -Example: -``` -User posts at 10:00 Poland time (UTC+2) -โ†“ -Docker container thinks local time is 08:00 UTC -โ†“ -SQLite datetime('now', 'localtime') stores: 08:00 -โ†“ -Display shows: 08:00 (wrong!) -``` - -## Solution -Set the Docker container timezone to Europe/Warsaw - -### 1. Updated Dockerfile (Production) - -```dockerfile -# Use Node.js 22.11.0 as the base image -FROM node:22.11.0 - -# Set timezone to Europe/Warsaw (Polish timezone) -ENV TZ=Europe/Warsaw -RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone - -# ... rest of Dockerfile -``` - -### 2. Updated Dockerfile.dev (Development) - -```dockerfile -# Use Node.js 22.11.0 as the base image -FROM node:22.11.0 - -# Set timezone to Europe/Warsaw (Polish timezone) -ENV TZ=Europe/Warsaw -RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone - -# ... rest of Dockerfile -``` - -### 3. Updated docker-compose.yml (Development) - -```yaml -environment: - - NODE_ENV=development - - TZ=Europe/Warsaw -``` - -### 4. Updated docker-compose.prod.yml (Production) - -```yaml -environment: - - NODE_ENV=production - - TZ=Europe/Warsaw - - NEXTAUTH_SECRET=... - - NEXTAUTH_URL=... -``` - -## How to Apply - -### Option 1: Rebuild Docker Images -```bash -# Stop containers -docker-compose down - -# Rebuild images -docker-compose build --no-cache - -# Start containers -docker-compose up -d -``` - -### Option 2: For Production Deployment -```bash -# Pull latest code with fixes -git pull - -# Rebuild production image -docker-compose -f docker-compose.prod.yml build --no-cache - -# Restart -docker-compose -f docker-compose.prod.yml up -d -``` - -## Verification - -After rebuilding and restarting, verify timezone inside container: - -```bash -# Check timezone -docker exec -it date -# Should show: Sat Oct 4 19:00:00 CEST 2025 - -# Check Node.js sees correct timezone -docker exec -it node -e "console.log(new Date().toLocaleString('pl-PL', {timeZone: 'Europe/Warsaw'}))" -# Should show current Polish time - -# Check SQLite sees correct timezone -docker exec -it node -e "const db = require('better-sqlite3')('./data/database.sqlite'); console.log(db.prepare(\"SELECT datetime('now', 'localtime')\").get());" -# Should show current Polish time -``` - -## Why This Works - -1. **TZ Environment Variable**: Tells all processes (including Node.js and SQLite) what timezone to use -2. **Symlink /etc/localtime**: Updates system timezone for the entire container -3. **echo TZ > /etc/timezone**: Ensures the timezone persists - -Now when SQLite uses `datetime('now', 'localtime')`: -- Container local time is 10:00 Poland time -- SQLite stores: 10:00 -- Display shows: 10:00 โœ… - -## Important Notes - -1. **Must rebuild images**: Just restarting containers is not enough - the timezone configuration is baked into the image -2. **All existing data**: Old notes will still show incorrect times (they were stored in UTC) -3. **New notes**: Will now display correctly -4. **DST handling**: Europe/Warsaw automatically handles Daylight Saving Time transitions - -## Alternative Approach (Not Recommended) - -Instead of changing container timezone, you could: -1. Store everything in UTC (like audit logs do with ISO format) -2. Always convert on display - -But this requires more code changes and the current approach is simpler and more maintainable. - -## Files Modified - -1. `Dockerfile` - Added TZ configuration -2. `Dockerfile.dev` - Added TZ configuration -3. `docker-compose.yml` - Added TZ environment variable -4. `docker-compose.prod.yml` - Added TZ environment variable - -## Testing Checklist - -After deployment: -- [ ] Container shows correct date/time with `docker exec date` -- [ ] Post a new note at known time (e.g., 10:30) -- [ ] Verify note displays the same time (10:30) -- [ ] Check both project notes and task notes -- [ ] Verify audit logs still work correctly -- [ ] Check task timestamps (date_started, date_completed) diff --git a/DROPDOWN_COMPLETION_STATUS.md b/DROPDOWN_COMPLETION_STATUS.md deleted file mode 100644 index b1da622..0000000 --- a/DROPDOWN_COMPLETION_STATUS.md +++ /dev/null @@ -1,152 +0,0 @@ -# โœ… Dropdown Consolidation - COMPLETED - -## Summary of Changes - -The project management interface has been successfully updated to eliminate redundant status displays by consolidating status badges and dropdowns into unified interactive components. - -## โœ… Components Successfully Updated - -### Task Status Dropdowns: - -- **ProjectTasksSection.js** โ†’ TaskStatusDropdownSimple โœ… -- **Tasks page** (`/tasks`) โ†’ TaskStatusDropdownSimple โœ… -- **ProjectTasksDashboard.js** โ†’ TaskStatusDropdownSimple โœ… -- **Main Dashboard** (`/`) โ†’ TaskStatusDropdownSimple โœ… (read-only mode) - -### Status Configurations: - -#### Task Statuses: - -- `pending` โ†’ Warning (yellow) -- `in_progress` โ†’ Primary (blue) -- `completed` โ†’ Success (green) -- `cancelled` โ†’ Danger (red) - -#### Project Statuses: - -- `registered` โ†’ Secondary (gray) -- `in_progress_design` โ†’ Primary (blue) -- `in_progress_construction` โ†’ Primary (blue) -- `fulfilled` โ†’ Success (green) - -## ๐ŸŽฏ Key Features Implemented - -### Unified Interface: - -- Single component serves as both status display and edit interface -- Click to expand dropdown with available status options -- Visual feedback with arrow rotation and hover effects -- Loading states during API updates - -### Debug Features (Current): - -- Red borders around dropdowns for visibility testing -- Yellow debug headers showing component type -- Console logging for click events and API calls -- Semi-transparent backdrop for easy identification - -### Z-Index Solution: - -- Dropdown: `z-[9999]` (maximum priority) -- Backdrop: `z-[9998]` (behind dropdown) - -## ๐Ÿงช Testing Instructions - -### 1. Access Test Pages: - -``` -http://localhost:3000/test-dropdowns # Isolated component testing -http://localhost:3000/projects # Project list with status dropdowns -http://localhost:3000/tasks # Task list with status dropdowns -http://localhost:3000/ # Main dashboard -``` - -### 2. Standalone HTML Tests: - -``` -test-dropdown-comprehensive.html # Complete functionality test -test-dropdown.html # Basic dropdown structure test -``` - -### 3. Test Checklist: - -- [ ] Dropdowns appear immediately when clicked -- [ ] Red borders and debug headers are visible -- [ ] Dropdowns appear above all other elements -- [ ] Clicking outside closes dropdowns -- [ ] Dropdowns work properly in table contexts -- [ ] API calls update status correctly -- [ ] Loading states show during updates -- [ ] Error handling reverts status on failure - -## ๐Ÿ“ Files Created/Modified - -### New Components: - -- `src/components/TaskStatusDropdownSimple.js` โœ… -- `src/components/ProjectStatusDropdownSimple.js` โœ… -- `src/app/test-dropdowns/page.js` โœ… - -### Updated Components: - -- `src/components/ProjectTasksSection.js` โœ… -- `src/app/tasks/page.js` โœ… -- `src/components/ProjectTasksDashboard.js` โœ… -- `src/app/page.js` โœ… - -### Test Files: - -- `test-dropdown-comprehensive.html` โœ… -- `test-dropdown.html` โœ… - -### Documentation: - -- `DROPDOWN_IMPLEMENTATION_SUMMARY.md` โœ… -- `DROPDOWN_COMPLETION_STATUS.md` โœ… (this file) - -## ๐Ÿš€ Next Steps (Production Polish) - -### 1. Remove Debug Features: - -```javascript -// Remove these debug elements: -- Red borders (border-2 border-red-500) -- Yellow debug headers -- Console.log statements -- Semi-transparent backdrop styling -``` - -### 2. Final Styling: - -```javascript -// Replace debug styles with: -border border-gray-200 // Subtle borders -shadow-lg // Professional shadows -Clean backdrop (transparent) -``` - -### 3. Performance Optimization: - -- Consider portal-based positioning for complex table layouts -- Add keyboard navigation (Enter/Escape keys) -- Implement click-outside using refs instead of global listeners - -### 4. Code Cleanup: - -- Remove original TaskStatusDropdown.js and ProjectStatusDropdown.js -- Rename Simple components to drop "Simple" suffix -- Update import statements across application - -## โœ… Success Criteria Met - -1. **Redundant UI Eliminated**: โœ… Single component replaces badge + dropdown pairs -2. **Z-Index Issues Resolved**: โœ… Dropdowns appear above all elements -3. **Table Compatibility**: โœ… Works properly in table/overflow contexts -4. **API Integration**: โœ… Status updates via PATCH/PUT requests -5. **Error Handling**: โœ… Reverts status on API failures -6. **Loading States**: โœ… Shows "Updating..." during API calls -7. **Consistent Styling**: โœ… Unified design patterns across components - -## ๐ŸŽ‰ Project Status: READY FOR TESTING - -The dropdown consolidation is complete and ready for user testing. All components have been updated to use the simplified, working versions with debug features enabled for validation. diff --git a/DROPDOWN_IMPLEMENTATION_SUMMARY.md b/DROPDOWN_IMPLEMENTATION_SUMMARY.md deleted file mode 100644 index 3a9056e..0000000 --- a/DROPDOWN_IMPLEMENTATION_SUMMARY.md +++ /dev/null @@ -1,142 +0,0 @@ -# Dropdown Consolidation - Implementation Summary - -## Problem Identified - -The project management interface had redundant status displays where both a status badge and a dropdown showing the same status information were displayed together. Additionally, there was a z-index issue where dropdowns appeared behind other elements. - -## Solution Implemented - -### 1. Created Unified Dropdown Components - -#### TaskStatusDropdown Components: - -- **TaskStatusDropdown.js** - Original enhanced component with portal positioning (currently has complexity issues) -- **TaskStatusDropdownSimple.js** - โœ… Simplified working version for testing - -#### ProjectStatusDropdown Components: - -- **ProjectStatusDropdown.js** - Original enhanced component with portal positioning (currently has complexity issues) -- **ProjectStatusDropdownSimple.js** - โœ… Simplified working version for testing - -### 2. Key Features of Unified Components - -#### Interactive Status Display: - -- Single component serves as both status badge and dropdown -- Click to expand dropdown with status options -- Visual feedback (arrow rotation, hover effects) -- Loading states during API calls - -#### Debugging Features (Current Implementation): - -- Console logging for click events -- Visible red border around dropdown for testing -- Yellow debug header showing dropdown is visible -- Semi-transparent backdrop for easy identification - -#### API Integration: - -- TaskStatusDropdown: PATCH `/api/project-tasks/{id}` -- ProjectStatusDropdown: PUT `/api/projects/{id}` -- Callback support for parent component refresh -- Error handling with status reversion - -### 3. Updated Components - -#### Currently Using Simplified Version: - -- โœ… **ProjectTasksSection.js** - Task table uses TaskStatusDropdownSimple -- โœ… **Test page created** - `/test-dropdowns` for isolated testing - -#### Still Using Original (Need to Update): - -- **ProjectTasksPage** (`/tasks`) - Uses TaskStatusDropdown -- **ProjectTasksDashboard** - Uses TaskStatusDropdown -- **Main Dashboard** (`/`) - Uses TaskStatusDropdown (read-only mode) -- **Project Detail Pages** - Uses ProjectStatusDropdown - -### 4. Configuration - -#### Task Status Options: - -- `pending` โ†’ Warning variant (yellow) -- `in_progress` โ†’ Primary variant (blue) -- `completed` โ†’ Success variant (green) -- `cancelled` โ†’ Danger variant (red) - -#### Project Status Options: - -- `registered` โ†’ Secondary variant (gray) -- `in_progress_design` โ†’ Primary variant (blue) -- `in_progress_construction` โ†’ Primary variant (blue) -- `fulfilled` โ†’ Success variant (green) - -### 5. Z-Index Solution - -- Dropdown: `z-[9999]` (maximum visibility) -- Backdrop: `z-[9998]` (behind dropdown) - -## Current Status - -### โœ… Working: - -- Simplified dropdown components compile without errors -- Basic dropdown structure and styling -- Debug features for testing -- Test page available at `/test-dropdowns` - -### ๐Ÿšง In Progress: - -- Testing dropdown visibility in browser -- Development server startup (terminal access issues) - -### ๐Ÿ“‹ Next Steps: - -1. **Test Simplified Components** - - - Verify dropdowns appear correctly - - Test click interactions - - Confirm API calls work - -2. **Replace Original Components** - - - Update remaining pages to use simplified versions - - Remove complex portal/positioning code if simple version works - -3. **Production Polish** - - - Remove debug features (red borders, console logs) - - Fine-tune styling and positioning - - Add portal-based positioning if needed for table overflow - -4. **Code Cleanup** - - Remove unused original components - - Clean up imports across all files - -## Testing Instructions - -1. **Access Test Page**: Navigate to `/test-dropdowns` -2. **Check Console**: Open browser dev tools (F12) โ†’ Console tab -3. **Test Interactions**: Click dropdowns to see debug messages -4. **Verify Visibility**: Look for red-bordered dropdowns with yellow debug headers - -## Files Modified - -### New Components: - -- `src/components/TaskStatusDropdownSimple.js` -- `src/components/ProjectStatusDropdownSimple.js` -- `src/app/test-dropdowns/page.js` - -### Updated Components: - -- `src/components/ProjectTasksSection.js` (using simple version) -- `src/components/TaskStatusDropdown.js` (enhanced but problematic) -- `src/components/ProjectStatusDropdown.js` (enhanced but problematic) - -### Test Files: - -- `test-dropdown.html` (standalone HTML test) -- `start-dev.bat` (development server script) - -The consolidation successfully eliminates duplicate status displays and provides a unified interface for status management across the application. diff --git a/EDGE_RUNTIME_FIX.md b/EDGE_RUNTIME_FIX.md deleted file mode 100644 index 3dac76e..0000000 --- a/EDGE_RUNTIME_FIX.md +++ /dev/null @@ -1,176 +0,0 @@ -# Edge Runtime Compatibility Fix - Final Solution - -## Problem Resolved - -The audit logging system was causing "Edge runtime does not support Node.js 'fs' module" errors because the `better-sqlite3` database module was being loaded in Edge Runtime contexts through static imports. - -## Root Cause - -The middleware imports `auth.js` โ†’ which imported `auditLog.js` โ†’ which had a static import of `db.js` โ†’ which imports `better-sqlite3`. This caused the entire SQLite module to be loaded even in Edge Runtime where it's not supported. - -## Final Solution - -### 1. Created Safe Audit Logging Module - -**File: `src/lib/auditLogSafe.js`** - -This module provides: - -- โœ… **No static database imports** - completely safe for Edge Runtime -- โœ… **Runtime detection** - automatically detects Edge vs Node.js -- โœ… **Graceful fallbacks** - console logging in Edge, database in Node.js -- โœ… **Constants always available** - `AUDIT_ACTIONS` and `RESOURCE_TYPES` -- โœ… **Async/await support** - works with modern API patterns - -```javascript -// Safe import that never causes Edge Runtime errors -import { - logAuditEventSafe, - AUDIT_ACTIONS, - RESOURCE_TYPES, -} from "./auditLogSafe.js"; - -// Works in any runtime -await logAuditEventSafe({ - action: AUDIT_ACTIONS.LOGIN, - userId: "user123", - resourceType: RESOURCE_TYPES.SESSION, -}); -``` - -### 2. Updated All Imports - -**Files Updated:** - -- `src/lib/auth.js` - Authentication logging -- `src/app/api/projects/route.js` - Project operations -- `src/app/api/projects/[id]/route.js` - Individual project operations -- `src/app/api/notes/route.js` - Note operations - -**Before:** - -```javascript -import { logApiAction, AUDIT_ACTIONS } from "@/lib/auditLog.js"; // โŒ Causes Edge Runtime errors -``` - -**After:** - -```javascript -import { logApiActionSafe, AUDIT_ACTIONS } from "@/lib/auditLogSafe.js"; // โœ… Edge Runtime safe -``` - -### 3. Runtime Behavior - -#### Edge Runtime - -- **Detection**: Automatic via `typeof EdgeRuntime !== 'undefined'` -- **Logging**: Console output only -- **Performance**: Zero database overhead -- **Errors**: None - completely safe - -#### Node.js Runtime - -- **Detection**: Automatic fallback when Edge Runtime not detected -- **Logging**: Full database functionality via dynamic import -- **Performance**: Full audit trail with database persistence -- **Errors**: Graceful handling with console fallback - -### 4. Migration Pattern - -The safe module uses a smart delegation pattern: - -```javascript -// In Edge Runtime: Console logging only -console.log(`[Audit] ${action} by user ${userId}`); - -// In Node.js Runtime: Try database, fallback to console -try { - const auditModule = await import("./auditLog.js"); - auditModule.logAuditEvent({ ...params }); -} catch (dbError) { - console.log("[Audit] Database logging failed, using console fallback"); -} -``` - -## Files Structure - -``` -src/lib/ -โ”œโ”€โ”€ auditLog.js # Original - Node.js only (database operations) -โ”œโ”€โ”€ auditLogSafe.js # New - Universal (Edge + Node.js compatible) -โ”œโ”€โ”€ auditLogEdge.js # Alternative - Edge-specific with API calls -โ””โ”€โ”€ auth.js # Updated to use safe imports -``` - -## Testing - -Run the compatibility test: - -```bash -node test-safe-audit-logging.mjs -``` - -**Expected Output:** - -``` -โœ… Safe module imported successfully -โœ… Edge Runtime logging successful (console only) -โœ… Node.js Runtime logging successful (database + console) -โœ… Constants accessible -``` - -## Verification Checklist - -โœ… **No more Edge Runtime errors** -โœ… **Middleware works without database dependencies** -โœ… **Authentication logging works in all contexts** -โœ… **API routes maintain full audit functionality** -โœ… **Constants available everywhere** -โœ… **Graceful degradation in Edge Runtime** -โœ… **Full functionality in Node.js Runtime** - -## Performance Impact - -- **Edge Runtime**: Minimal - only console logging -- **Node.js Runtime**: Same as before - full database operations -- **Import cost**: Near zero - no static database imports -- **Memory usage**: Significantly reduced in Edge Runtime - -## Migration Guide - -To update existing code: - -1. **Replace imports:** - - ```javascript - // Old - import { logApiAction } from "@/lib/auditLog.js"; - - // New - import { logApiActionSafe } from "@/lib/auditLogSafe.js"; - ``` - -2. **Update function calls:** - - ```javascript - // Old - logApiAction(req, action, type, id, session, details); - - // New - await logApiActionSafe(req, action, type, id, session, details); - ``` - -3. **Add runtime exports** (for API routes): - ```javascript - export const runtime = "nodejs"; // For database-heavy routes - ``` - -## Best Practices Applied - -1. **Separation of Concerns**: Safe module for universal use, full module for Node.js -2. **Dynamic Imports**: Database modules loaded only when needed -3. **Runtime Detection**: Automatic environment detection -4. **Graceful Degradation**: Meaningful fallbacks in constrained environments -5. **Error Isolation**: Audit failures don't break main application flow - -The application now handles both Edge and Node.js runtimes seamlessly with zero Edge Runtime errors! ๐ŸŽ‰ diff --git a/EDGE_RUNTIME_FIX_FINAL.md b/EDGE_RUNTIME_FIX_FINAL.md deleted file mode 100644 index 689b60c..0000000 --- a/EDGE_RUNTIME_FIX_FINAL.md +++ /dev/null @@ -1,161 +0,0 @@ -# Final Edge Runtime Fix - Audit Logging System - -## โœ… **Issue Resolved** - -The Edge Runtime error has been completely fixed! The audit logging system now works seamlessly across all Next.js runtime environments. - -## ๐Ÿ”ง **Final Implementation** - -### **Problem Summary** - -- Edge Runtime was trying to load `better-sqlite3` (Node.js fs module) -- Static imports in middleware caused the entire dependency chain to load -- `middleware.js` โ†’ `auth.js` โ†’ `auditLog.js` โ†’ `db.js` โ†’ `better-sqlite3` - -### **Solution Implemented** - -#### 1. **Made All Functions Async** - -```javascript -// Before: Synchronous with require() -export function logAuditEvent() { - const { default: db } = require("./db.js"); -} - -// After: Async with dynamic import -export async function logAuditEvent() { - const { default: db } = await import("./db.js"); -} -``` - -#### 2. **Runtime Detection & Graceful Fallbacks** - -```javascript -export async function logAuditEvent(params) { - try { - // Edge Runtime detection - if ( - typeof EdgeRuntime !== "undefined" || - process.env.NEXT_RUNTIME === "edge" - ) { - console.log(`[Audit Log - Edge Runtime] ${action} by user ${userId}`); - return; // Graceful exit - } - - // Node.js Runtime: Full database functionality - const { default: db } = await import("./db.js"); - // ... database operations - } catch (error) { - console.error("Failed to log audit event:", error); - // Non-breaking error handling - } -} -``` - -#### 3. **Safe Wrapper Module (`auditLogSafe.js`)** - -```javascript -export async function logAuditEventSafe(params) { - console.log(`[Audit] ${action} by user ${userId}`); // Always log to console - - if (typeof EdgeRuntime !== "undefined") { - return; // Edge Runtime: Console only - } - - try { - const auditModule = await import("./auditLog.js"); - await auditModule.logAuditEvent(params); // Node.js: Database + console - } catch (error) { - console.log("[Audit] Database logging failed, using console fallback"); - } -} -``` - -## ๐ŸŽฏ **Runtime Behavior** - -| Runtime | Behavior | Database | Console | Errors | -| ----------- | ------------------------ | -------- | ------- | ---------------------- | -| **Edge** | Console logging only | โŒ | โœ… | โŒ Zero errors | -| **Node.js** | Full audit functionality | โœ… | โœ… | โŒ Full error handling | - -## โœ… **Test Results** - -```bash -$ node test-safe-audit-logging.mjs - -Testing Safe Audit Logging... - -1. Testing safe module import... -โœ… Safe module imported successfully - Available actions: 27 - Available resource types: 8 - -2. Testing in simulated Edge Runtime... -[Audit] project_view by user anonymous on project:test-123 -[Audit] Edge Runtime detected - console logging only -โœ… Edge Runtime logging successful (console only) - -3. Testing in simulated Node.js Runtime... -[Audit] project_create by user anonymous on project:test-456 -Audit log: project_create by user anonymous on project:test-456 -โœ… Node.js Runtime logging successful (database + console) - -4. Testing constants accessibility... -โœ… Constants accessible: - LOGIN action: login - PROJECT resource: project - NOTE_CREATE action: note_create - -โœ… Safe Audit Logging test completed! - -Key features verified: -- โœ… No static database imports -- โœ… Edge Runtime compatibility -- โœ… Graceful fallbacks -- โœ… Constants always available -- โœ… Async/await support - -The middleware should now work without Edge Runtime errors! -``` - -## ๐Ÿ“ **Files Updated** - -### **Core Audit System** - -- โœ… `src/lib/auditLog.js` - Made all functions async, removed static imports -- โœ… `src/lib/auditLogSafe.js` - New Edge-compatible wrapper module - -### **Authentication** - -- โœ… `src/lib/auth.js` - Updated to use safe audit logging - -### **API Routes** - -- โœ… `src/app/api/audit-logs/route.js` - Updated for async functions -- โœ… `src/app/api/audit-logs/stats/route.js` - Updated for async functions -- โœ… `src/app/api/audit-logs/log/route.js` - Updated for async functions -- โœ… `src/app/api/projects/route.js` - Using safe audit logging -- โœ… `src/app/api/projects/[id]/route.js` - Using safe audit logging -- โœ… `src/app/api/notes/route.js` - Using safe audit logging - -## ๐Ÿš€ **Benefits Achieved** - -1. **โœ… Zero Edge Runtime Errors** - No more fs module conflicts -2. **โœ… Universal Compatibility** - Works in any Next.js runtime environment -3. **โœ… No Functionality Loss** - Full audit trail in production (Node.js runtime) -4. **โœ… Graceful Degradation** - Meaningful console logging in Edge Runtime -5. **โœ… Performance Optimized** - No unnecessary database loads in Edge Runtime -6. **โœ… Developer Friendly** - Clear logging shows what's happening in each runtime - -## ๐ŸŽ‰ **Final Status** - -**The audit logging system is now production-ready and Edge Runtime compatible!** - -- **Middleware**: โœ… Works without errors -- **Authentication**: โœ… Logs login/logout events -- **API Routes**: โœ… Full audit trail for CRUD operations -- **Admin Interface**: โœ… View audit logs at `/admin/audit-logs` -- **Edge Runtime**: โœ… Zero errors, console fallbacks -- **Node.js Runtime**: โœ… Full database functionality - -Your application should now run perfectly without any Edge Runtime errors while maintaining comprehensive audit logging! ๐ŸŽŠ diff --git a/INTEGRATION_COMPLETE.md b/INTEGRATION_COMPLETE.md deleted file mode 100644 index 75bb595..0000000 --- a/INTEGRATION_COMPLETE.md +++ /dev/null @@ -1,137 +0,0 @@ -# Polish Geospatial Layers Integration - COMPLETE SUCCESS! ๐ŸŽ‰ - -## โœ… Mission Accomplished - -All Polish geospatial layers including Google Maps have been successfully integrated into the main project's mapping system. The integration maintains proper transparency handling and provides a comprehensive mapping solution. - -## ๐Ÿš€ What Was Implemented - -### 1. Enhanced Layer Configuration (`mapLayers.js`) -**Before**: Only basic OpenStreetMap + simple Polish orthophoto -**After**: 8 base layers + 6 overlay layers with full transparency support - -### 2. Updated Main Map Components -- **`LeafletMap.js`** - Main project map component โœ… -- **`EnhancedLeafletMap.js`** - Enhanced map variant โœ… -- Added `WMSTileLayer` import and proper overlay handling - -### 3. Comprehensive Layer Selection - -#### Base Layers (8 total) -1. **OpenStreetMap** (default) -2. **๐Ÿ‡ต๐Ÿ‡ฑ Polish Orthophoto (Standard)** - WMTS format -3. **๐Ÿ‡ต๐Ÿ‡ฑ Polish Orthophoto (High Resolution)** - WMTS format -4. **๐ŸŒ Google Satellite** - Global satellite imagery -5. **๐ŸŒ Google Hybrid** - Satellite + roads -6. **๐ŸŒ Google Roads** - Road map -7. **Satellite (Esri)** - Alternative satellite -8. **Topographic** - CartoDB topographic - -#### Overlay Layers (6 total with transparency) -1. **๐Ÿ“‹ Polish Cadastral Data** (WMS, 80% opacity) -2. **๐Ÿ—๏ธ Polish Spatial Planning** (WMS, 70% opacity) -3. **๐Ÿ›ฃ๏ธ LP-Portal Roads** (WMS, 90% opacity) -4. **๐Ÿท๏ธ LP-Portal Street Names** (WMS, 100% opacity) -5. **๐Ÿ“ LP-Portal Parcels** (WMS, 60% opacity) -6. **๐Ÿ“ LP-Portal Survey Markers** (WMS, 80% opacity) - -## ๐ŸŽฏ Key Features Implemented - -### Layer Control Interface -- **๐Ÿ“š Layer Control Button** in top-right corner -- **Radio buttons** for base layers (mutually exclusive) -- **Checkboxes** for overlays (can combine multiple) -- **Emoji icons** for easy layer identification - -### Transparency System -- **Base layers**: Fully opaque backgrounds -- **Overlay layers**: Each with optimized transparency: - - Property boundaries: Semi-transparent for visibility - - Planning zones: Semi-transparent for context - - Roads: Mostly opaque for navigation - - Text labels: Fully opaque for readability - - Survey data: Semi-transparent for reference - -### Technical Excellence -- **WMTS Integration**: Proper KVP format for Polish orthophoto -- **WMS Integration**: Transparent PNG overlays with correct parameters -- **Performance**: Efficient tile loading and layer switching -- **Compatibility**: Works with existing project structure -- **SSR Safe**: Proper dynamic imports for Next.js - -## ๐ŸŒ Geographic Coverage - -### Poland-Specific Layers -- **Polish Orthophoto**: Complete national coverage at high resolution -- **Cadastral Data**: Official property boundaries nationwide -- **Spatial Planning**: Zoning data where available -- **LP-Portal**: Municipal data for specific regions - -### Global Layers -- **Google Services**: Worldwide satellite and road data -- **Esri Satellite**: Global high-resolution imagery -- **OpenStreetMap**: Community-driven global mapping - -## ๐Ÿ“ฑ Where It's Available - -### Main Project Maps -- **`/projects/map`** - Projects overview map โœ… -- **Individual project cards** - Project location maps โœ… -- **All existing map components** - Enhanced with new layers โœ… - -### Demo/Test Pages (Still Available) -- **`/comprehensive-polish-map`** - Full-featured demo -- **`/test-polish-map`** - Layer comparison -- **`/debug-polish-orthophoto`** - Technical testing - -## ๐Ÿ”ง Code Changes Summary - -### Layer Configuration (`mapLayers.js`) -```javascript -// Added 6 new base layers including Polish orthophoto + Google -// Added 6 overlay layers with WMS configuration -// Proper transparency and opacity settings -``` - -### Map Components (`LeafletMap.js`, `EnhancedLeafletMap.js`) -```javascript -// Added WMSTileLayer import -// Added Overlay component support -// Layer control with both BaseLayer and Overlay -// Transparency parameter handling -``` - -## ๐ŸŽฏ User Experience - -### Easy Layer Selection -1. Click **๐Ÿ“š** layer control button -2. Select base layer (aerial photos, satellite, roads, etc.) -3. Check/uncheck overlays (property boundaries, planning, etc.) -4. Layers update instantly - -### Visual Clarity -- **Emojis** make layer types instantly recognizable -- **Proper transparency** prevents overlays from obscuring base maps -- **Performance** optimized for smooth switching - -## ๐Ÿš€ Ready for Production - -โœ… **Integration Complete**: All layers working in main project maps -โœ… **Transparency Handled**: Overlays properly configured with opacity -โœ… **Performance Optimized**: Efficient loading and switching -โœ… **User-Friendly**: Clear interface with emoji identifiers -โœ… **Tested**: Development server running successfully -โœ… **Documented**: Comprehensive guides available - -## ๐ŸŽ‰ Final Result - -The project now has **enterprise-grade Polish geospatial capabilities** integrated directly into the main mapping system. Users can access: - -- **High-resolution Polish orthophoto** from official government sources -- **Official cadastral data** for property boundaries -- **Spatial planning information** for zoning -- **Municipal data** from LP-Portal -- **Global satellite imagery** from Google and Esri -- **Full transparency control** for overlay combinations - -**Mission: ACCOMPLISHED!** ๐Ÿš€๐Ÿ—บ๏ธ๐Ÿ‡ต๐Ÿ‡ฑ diff --git a/INTEGRATION_SUMMARY.md b/INTEGRATION_SUMMARY.md deleted file mode 100644 index bb86898..0000000 --- a/INTEGRATION_SUMMARY.md +++ /dev/null @@ -1,116 +0,0 @@ -# Polish Geospatial Layers Integration - Project Maps Complete! ๐ŸŽ‰ - -## โœ… Successfully Integrated Into Main Project Maps - -All Polish geospatial layers and Google layers have been successfully integrated into the main project's mapping system. - -## ๐Ÿ—บ๏ธ Available Layers in Project Maps - -### Base Layers (Mutually Exclusive) -1. **OpenStreetMap** - Default layer -2. **๐Ÿ‡ต๐Ÿ‡ฑ Polish Orthophoto (Standard)** - High-quality aerial imagery -3. **๐Ÿ‡ต๐Ÿ‡ฑ Polish Orthophoto (High Resolution)** - Ultra-high resolution aerial imagery -4. **๐ŸŒ Google Satellite** - Google satellite imagery -5. **๐ŸŒ Google Hybrid** - Google satellite with roads overlay -6. **๐ŸŒ Google Roads** - Google road map -7. **Satellite (Esri)** - Esri world imagery -8. **Topographic** - CartoDB Voyager topographic map - -### Overlay Layers (Can be Combined with Transparency) -1. **๐Ÿ“‹ Polish Cadastral Data** - Property boundaries and parcel information (80% opacity) -2. **๐Ÿ—๏ธ Polish Spatial Planning** - Zoning and urban planning data (70% opacity) -3. **๐Ÿ›ฃ๏ธ LP-Portal Roads** - Detailed road network (90% opacity) -4. **๐Ÿท๏ธ LP-Portal Street Names** - Street names and descriptions (100% opacity) -5. **๐Ÿ“ LP-Portal Parcels** - Municipal property parcels (60% opacity) -6. **๐Ÿ“ LP-Portal Survey Markers** - Survey markers and reference points (80% opacity) - -## ๐Ÿ“ Updated Files - -### Core Map Components -- **`src/components/ui/LeafletMap.js`** - Main project map component โœ… -- **`src/components/ui/EnhancedLeafletMap.js`** - Enhanced map component โœ… -- **`src/components/ui/mapLayers.js`** - Layer configuration โœ… - -### Map Usage in Project -- **`src/app/projects/map/page.js`** - Projects map page (uses LeafletMap) -- **`src/components/ui/ProjectMap.js`** - Individual project maps (uses LeafletMap) - -## ๐Ÿš€ How It Works - -### Layer Control -- **Layer Control Button** (๐Ÿ“š) appears in top-right corner of maps -- **Base Layers** - Radio buttons (only one can be selected) -- **Overlay Layers** - Checkboxes (multiple can be selected) - -### Transparency Handling -- **Base layers** are fully opaque (no transparency) -- **Overlay layers** have appropriate transparency levels: - - Cadastral data: Semi-transparent for property boundaries - - Planning data: Semi-transparent for zoning information - - Roads: Mostly opaque for visibility - - Street names: Fully opaque for text readability - - Parcels: Semi-transparent for boundary visualization - - Survey markers: Semi-transparent for reference points - -### Automatic Integration -All existing project maps now have access to: -- Polish orthophoto layers -- Google satellite/road layers -- Polish government WMS overlays -- LP-Portal municipal data overlays - -## ๐ŸŽฏ Benefits - -1. **Enhanced Mapping Capabilities**: Rich selection of base layers for different use cases -2. **Polish-Specific Data**: Access to official Polish cadastral and planning data -3. **Transparency Support**: Overlays work correctly with transparency -4. **Maintained Performance**: Layers load efficiently and switch smoothly -5. **User-Friendly**: Clear naming with emojis for easy identification - -## ๐ŸŒ Geographic Coverage - -- **Polish Orthophoto**: Complete coverage of Poland -- **Polish Cadastral**: Official property boundaries across Poland -- **Polish Planning**: Zoning data where available -- **LP-Portal**: Municipal data (specific regions) -- **Google Layers**: Global coverage -- **Esri Satellite**: Global coverage - -## ๐Ÿ“ฑ Test Locations - -Perfect locations to test all layers: -- **Krakรณw**: [50.0647, 19.9450] - Historic center with detailed cadastral data -- **Warszawa**: [52.2297, 21.0122] - Capital city with planning data -- **Gdaล„sk**: [54.3520, 18.6466] - Port city with orthophoto coverage -- **Wrocล‚aw**: [51.1079, 17.0385] - University city -- **Poznaล„**: [52.4064, 16.9252] - Industrial center - -## ๐Ÿ”ง Technical Implementation - -### WMTS Integration -- Polish orthophoto uses proper WMTS KVP format -- EPSG:3857 coordinate system for Leaflet compatibility -- Standard 256x256 tile size for optimal performance - -### WMS Overlay Integration -- Transparent PNG format for overlays -- Proper parameter configuration for each service -- Optimized opacity levels for each overlay type -- Tiled requests for better performance - -### React/Leaflet Architecture -- Uses `react-leaflet` components: `TileLayer` and `WMSTileLayer` -- Proper layer control with `BaseLayer` and `Overlay` components -- Icon fixes for marker display -- SSR-safe dynamic imports - -## ๐ŸŽ‰ Status: COMPLETE - -โœ… All Polish geospatial layers integrated -โœ… Google layers integrated -โœ… Transparency properly handled -โœ… Layer control working -โœ… Project maps updated -โœ… Documentation complete - -The main project maps now have comprehensive Polish geospatial capabilities with proper transparency support! ๐Ÿš€ diff --git a/MERGE_COMPLETE.md b/MERGE_COMPLETE.md deleted file mode 100644 index 08d9602..0000000 --- a/MERGE_COMPLETE.md +++ /dev/null @@ -1,47 +0,0 @@ -# Merge Complete - auth2 to main - -## Summary -Successfully merged the `auth2` branch into the `main` branch on **2024-12-29**. - -## What was merged -The `auth2` branch contained extensive authentication and authorization features: - -### Core Features Added: -1. **Authentication System** - Complete NextAuth.js implementation with database sessions -2. **Authorization & Access Control** - Role-based permissions (admin, user, guest) -3. **User Management** - Admin interface for user creation, editing, and role management -4. **Audit Logging** - Comprehensive logging of all user actions and system events -5. **Edge Runtime Compatibility** - Fixed SSR and build issues for production deployment - -### Technical Improvements: -- **SSR Fixes** - Resolved all Server-Side Rendering issues with map components and auth pages -- **Build Optimization** - Project now builds cleanly without errors -- **UI/UX Preservation** - Maintained all original functionality, especially the projects map view -- **Security Enhancements** - Added middleware for route protection and audit logging - -## Files Modified/Added: -- **98 files changed** with 9,544 additions and 658 deletions -- Major additions include authentication pages, admin interfaces, API routes, and middleware -- All test/debug pages moved to `debug-disabled/` folder to keep them out of production builds - -## Verification: -โœ… Build completed successfully (`npm run build`) -โœ… Development server starts without errors (`npm run dev`) -โœ… All pages load correctly, including `/projects/map` -โœ… Original UI/UX functionality preserved -โœ… Authentication and authorization working as expected - -## Post-Merge Status: -- **Current branch**: `main` -- **Remote status**: All changes pushed to origin/main -- **Ready for production**: Yes, all SSR issues resolved -- **Authentication**: Fully functional with admin panel at `/admin/users` - -## Next Steps: -1. Test the production deployment -2. Create initial admin user using `node scripts/create-admin.js` -3. Monitor audit logs for any issues -4. Consider cleaning up old test files in future iterations - ---- -*Merge completed by GitHub Copilot on 2024-12-29* diff --git a/MERGE_PREPARATION_SUMMARY.md b/MERGE_PREPARATION_SUMMARY.md deleted file mode 100644 index a23b049..0000000 --- a/MERGE_PREPARATION_SUMMARY.md +++ /dev/null @@ -1,90 +0,0 @@ -# Branch Merge Preparation Summary - -## โœ… Completed Tasks - -### 1. Build Issues Fixed -- **SSR Issues**: Fixed server-side rendering issues with Leaflet map components -- **useSearchParams**: Added Suspense boundaries to all pages using useSearchParams -- **Dynamic Imports**: Implemented proper dynamic imports for map components -- **Build Success**: Project now builds successfully without errors - -### 2. Code Quality Improvements -- **README Updated**: Comprehensive documentation reflecting current project state -- **Project Structure**: Updated project structure documentation -- **API Documentation**: Added complete API endpoint documentation -- **Clean Build**: All pages compile and build correctly - -### 3. Debug Pages Management -- **Temporary Relocation**: Moved debug/test pages to `debug-disabled/` folder -- **Build Optimization**: Removed non-production pages from build process -- **Development Tools**: Preserved debug functionality for future development - -### 4. Authentication & Authorization -- **Auth Pages Fixed**: All authentication pages now build correctly -- **Suspense Boundaries**: Proper error boundaries for auth components -- **Session Management**: Maintained existing auth functionality - -## ๐Ÿ” Current State - -### Build Status -- โœ… **npm run build**: Successful -- โœ… **34 pages**: All pages compile -- โœ… **Static Generation**: Working correctly -- โš ๏ธ **ESLint Warning**: Parser serialization issue (non-blocking) - -### Branch Status -- **Branch**: `auth2` -- **Status**: Ready for merge to main -- **Commit**: `faeb1ca` - "Prepare branch for merge to main" -- **Files Changed**: 13 files modified/moved - -## ๐Ÿš€ Next Steps for Merge - -### 1. Pre-merge Checklist -- [x] All build errors resolved -- [x] Documentation updated -- [x] Non-production code moved -- [x] Changes committed -- [ ] Final testing (recommended) -- [ ] Merge to main branch - -### 2. Post-merge Tasks -- [ ] Re-enable debug pages if needed (move back from `debug-disabled/`) -- [ ] Fix ESLint parser configuration -- [ ] Add integration tests -- [ ] Deploy to production - -### 3. Optional Improvements -- [ ] Fix ESLint configuration for better linting -- [ ] Add more comprehensive error handling -- [ ] Optimize bundle size -- [ ] Add more unit tests - -## ๐Ÿ“ Files Modified - -### Core Changes -- `README.md` - Updated comprehensive documentation -- `src/app/auth/error/page.js` - Added Suspense boundary -- `src/app/auth/signin/page.js` - Added Suspense boundary -- `src/app/projects/[id]/page.js` - Fixed dynamic import -- `src/app/projects/map/page.js` - Added Suspense boundary -- `src/components/ui/ClientProjectMap.js` - New client component wrapper - -### Debug Pages (Temporarily Moved) -- `debug-disabled/debug-polish-orthophoto/` - Polish orthophoto debug -- `debug-disabled/test-polish-orthophoto/` - Polish orthophoto test -- `debug-disabled/test-polish-map/` - Polish map test -- `debug-disabled/test-improved-wmts/` - WMTS test -- `debug-disabled/comprehensive-polish-map/` - Comprehensive map test - -## ๐ŸŽฏ Recommendation - -**The branch is now ready for merge to main.** All critical build issues have been resolved, and the project builds successfully. The debug pages have been temporarily moved to prevent build issues while preserving their functionality for future development. - -To proceed with the merge: -1. Switch to main branch: `git checkout main` -2. Merge auth2 branch: `git merge auth2` -3. Push to origin: `git push origin main` -4. Deploy if needed - -The project is now in a stable state with comprehensive authentication, project management, and mapping functionality. diff --git a/POLISH_LAYERS_IMPLEMENTATION.md b/POLISH_LAYERS_IMPLEMENTATION.md deleted file mode 100644 index 08a11a1..0000000 --- a/POLISH_LAYERS_IMPLEMENTATION.md +++ /dev/null @@ -1,139 +0,0 @@ -# Polish Geospatial Layers Integration Guide - -## ๐ŸŽฏ All 4+ Polish Layers Successfully Implemented! - -This document shows how to use the comprehensive Polish geospatial layers that have been converted from your OpenLayers implementation to work with Leaflet/React. - -## ๐Ÿ“ฆ Available Components - -### Complete Map Components -- `ComprehensivePolishMap.js` - Full-featured map with all layers -- `AdvancedPolishOrthophotoMap.js` - Advanced map with overlays -- `PolishOrthophotoMap.js` - Basic map with Polish orthophoto - -### Individual Layer Components -- `PolishGeoLayers.js` - Individual layer components for custom integration - -## ๐Ÿ—บ๏ธ Implemented Layers - -### Base Layers (WMTS) -1. **Polish Orthophoto Standard Resolution** โœ… - - URL: `https://mapy.geoportal.gov.pl/wss/service/PZGIK/ORTO/WMTS/StandardResolution` - - Format: JPEG, Max Zoom: 19 - -2. **Polish Orthophoto High Resolution** โœ… - - URL: `https://mapy.geoportal.gov.pl/wss/service/PZGIK/ORTO/WMTS/HighResolution` - - Format: JPEG, Max Zoom: 19 - -### Overlay Layers (WMS) - -3. **Polish Cadastral Data (Dziaล‚ki)** โœ… - - Service: GUGiK Krajowa Integracja Ewidencji Gruntรณw - - Layers: Property boundaries, parcels, buildings - - Format: PNG (transparent) - -4. **Polish Spatial Planning (MPZT)** โœ… - - Service: Geoportal Spatial Planning Integration - - Layers: Zoning, planning boundaries, land use - - Format: PNG (transparent) - -### Additional LP-Portal Layers -5. **LP-Portal Roads** โœ… -6. **LP-Portal Street Names** โœ… -7. **LP-Portal Property Parcels** โœ… -8. **LP-Portal Survey Markers** โœ… - -## ๐Ÿš€ How to Use - -### Option 1: Use Complete Component -```jsx -import ComprehensivePolishMap from '../components/ui/ComprehensivePolishMap'; - -export default function MyPage() { - return ( -
- -
- ); -} -``` - -### Option 2: Use Individual Layers -```jsx -import { MapContainer, LayersControl } from 'react-leaflet'; -import { - PolishOrthophotoStandard, - PolishCadastralData, - LPPortalRoads -} from '../components/ui/PolishGeoLayers'; - -export default function CustomMap() { - const { BaseLayer, Overlay } = LayersControl; - - return ( - - - - - - - - - - - - - - - - ); -} -``` - -## ๐Ÿ“ Test Locations - -Good locations to test the layers: -- **Krakรณw**: [50.0647, 19.9450] - Historic center -- **Warszawa**: [52.2297, 21.0122] - Capital city -- **Gdaล„sk**: [54.3520, 18.6466] - Port city -- **Wrocล‚aw**: [51.1079, 17.0385] - University city -- **Poznaล„**: [52.4064, 16.9252] - Industrial center - -## โš™๏ธ Technical Details - -### WMTS Implementation -- Uses proper KVP (Key-Value Pair) URL format -- EPSG:3857 coordinate system for Leaflet compatibility -- Standard tile size (256x256) - -### WMS Implementation -- Transparent PNG overlays -- Proper parameter configuration -- Tiled requests for better performance - -### Performance Considerations -- All layers use standard web projections -- Optimized for React/Leaflet -- Minimal additional dependencies (only proj4 for future enhancements) - -## ๐ŸŽ‰ Success! - -All layers from your OpenLayers implementation are now working in your Leaflet-based React/Next.js project: - -โœ… Polish Orthophoto (Standard & High-Res) -โœ… Polish Cadastral Data (Property boundaries) -โœ… Polish Spatial Planning (Zoning data) -โœ… LP-Portal Municipal Data (Roads, names, parcels, surveys) - -The implementation maintains the same functionality as your original OpenLayers code while being fully compatible with your existing React/Leaflet architecture. - -## ๐Ÿ“ฑ Test Pages Available - -- `/comprehensive-polish-map` - Full featured map -- `/test-polish-map` - Basic comparison -- `/test-improved-wmts` - Technical testing diff --git a/add-assignable-column.mjs b/add-assignable-column.mjs deleted file mode 100644 index dfbdb64..0000000 --- a/add-assignable-column.mjs +++ /dev/null @@ -1,18 +0,0 @@ -import db from "./src/lib/db.js"; - -console.log("Adding can_be_assigned column to users table..."); - -// Add the new column -db.prepare(` - ALTER TABLE users - ADD COLUMN can_be_assigned INTEGER DEFAULT 1 -`).run(); - -// Set admin users to not be assignable by default -db.prepare(` - UPDATE users - SET can_be_assigned = 0 - WHERE role = 'admin' -`).run(); - -console.log("Migration completed. Admin users are now not assignable by default."); \ No newline at end of file diff --git a/check-audit-db.mjs b/check-audit-db.mjs deleted file mode 100644 index 316d113..0000000 --- a/check-audit-db.mjs +++ /dev/null @@ -1,56 +0,0 @@ -import { readFileSync } from "fs"; -import Database from "better-sqlite3"; - -// Check database directly -const dbPath = "./data/database.sqlite"; -const db = new Database(dbPath); - -console.log("Checking audit logs table...\n"); - -// Check table schema -const schema = db - .prepare( - "SELECT sql FROM sqlite_master WHERE type='table' AND name='audit_logs'" - ) - .get(); -console.log("Table schema:"); -console.log(schema?.sql || "Table not found"); - -console.log("\n" + "=".repeat(50) + "\n"); - -// Get some audit logs -const logs = db - .prepare("SELECT * FROM audit_logs ORDER BY timestamp DESC LIMIT 5") - .all(); -console.log(`Found ${logs.length} audit log entries:`); - -logs.forEach((log, index) => { - console.log(`\n${index + 1}. ID: ${log.id}`); - console.log(` Timestamp: ${log.timestamp}`); - console.log(` User ID: ${log.user_id || "NULL"}`); - console.log(` Action: ${log.action}`); - console.log(` Resource Type: ${log.resource_type}`); - console.log(` Resource ID: ${log.resource_id || "N/A"}`); - console.log(` IP Address: ${log.ip_address || "N/A"}`); - console.log(` User Agent: ${log.user_agent || "N/A"}`); - console.log(` Details: ${log.details || "NULL"}`); - console.log(` Details type: ${typeof log.details}`); -}); - -// Count null user_ids -const nullUserCount = db - .prepare("SELECT COUNT(*) as count FROM audit_logs WHERE user_id IS NULL") - .get(); -const totalCount = db.prepare("SELECT COUNT(*) as count FROM audit_logs").get(); - -console.log(`\n${"=".repeat(50)}`); -console.log(`Total audit logs: ${totalCount.count}`); -console.log(`Logs with NULL user_id: ${nullUserCount.count}`); -console.log( - `Percentage with NULL user_id: ${( - (nullUserCount.count / totalCount.count) * - 100 - ).toFixed(2)}%` -); - -db.close(); diff --git a/check-columns.mjs b/check-columns.mjs deleted file mode 100644 index 5a98918..0000000 --- a/check-columns.mjs +++ /dev/null @@ -1,13 +0,0 @@ -import db from "./src/lib/db.js"; - -console.log("Checking projects table structure:"); -const tableInfo = db.prepare("PRAGMA table_info(projects)").all(); -console.log(JSON.stringify(tableInfo, null, 2)); - -// Check if created_at and updated_at columns exist -const hasCreatedAt = tableInfo.some((col) => col.name === "created_at"); -const hasUpdatedAt = tableInfo.some((col) => col.name === "updated_at"); - -console.log("\nColumn existence check:"); -console.log("created_at exists:", hasCreatedAt); -console.log("updated_at exists:", hasUpdatedAt); diff --git a/check-contacts.mjs b/check-contacts.mjs deleted file mode 100644 index c48c11c..0000000 --- a/check-contacts.mjs +++ /dev/null @@ -1,22 +0,0 @@ -import db from './src/lib/db.js'; - -console.log('Checking contacts in database...\n'); - -const contacts = db.prepare('SELECT contact_id, name, phone, email, is_active, contact_type FROM contacts LIMIT 10').all(); - -console.log(`Total contacts found: ${contacts.length}\n`); - -if (contacts.length > 0) { - console.log('Sample contacts:'); - contacts.forEach(c => { - console.log(` ID: ${c.contact_id}, Name: ${c.name}, Phone: ${c.phone || 'N/A'}, Email: ${c.email || 'N/A'}, Active: ${c.is_active}, Type: ${c.contact_type}`); - }); -} else { - console.log('No contacts found in database!'); -} - -const activeCount = db.prepare('SELECT COUNT(*) as count FROM contacts WHERE is_active = 1').get(); -console.log(`\nActive contacts: ${activeCount.count}`); - -const totalCount = db.prepare('SELECT COUNT(*) as count FROM contacts').get(); -console.log(`Total contacts: ${totalCount.count}`); diff --git a/check-project-dates.mjs b/check-project-dates.mjs deleted file mode 100644 index afe1278..0000000 --- a/check-project-dates.mjs +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/env node - -import db from "./src/lib/db.js"; -import { parseISO, isAfter, startOfDay, addDays } from "date-fns"; - -const today = startOfDay(new Date()); -const threeDaysFromNow = addDays(today, 3); -const oneDayFromNow = addDays(today, 1); - -console.log(`Today: ${today.toISOString().split('T')[0]}`); -console.log(`3 days from now: ${threeDaysFromNow.toISOString().split('T')[0]}`); -console.log(`1 day from now: ${oneDayFromNow.toISOString().split('T')[0]}`); - -const projects = db.prepare(` - SELECT project_name, finish_date, project_status - FROM projects - WHERE finish_date IS NOT NULL - AND project_status != 'fulfilled' - AND project_status != 'cancelled' - ORDER BY finish_date ASC -`).all(); - -console.log(`\nFound ${projects.length} active projects with due dates:`); - -projects.forEach(project => { - try { - const finishDate = parseISO(project.finish_date); - const finishDateStart = startOfDay(finishDate); - - const isDueIn3Days = finishDateStart.getTime() === threeDaysFromNow.getTime(); - const isDueIn1Day = finishDateStart.getTime() === oneDayFromNow.getTime(); - const isOverdue = isAfter(today, finishDateStart); - - let status = ''; - if (isDueIn3Days) status = 'โš ๏ธ DUE IN 3 DAYS'; - else if (isDueIn1Day) status = '๐Ÿšจ DUE IN 1 DAY'; - else if (isOverdue) status = 'โŒ OVERDUE'; - else status = '๐Ÿ“… Future'; - - console.log(`${status} - ${project.project_name}: ${project.finish_date.split('T')[0]} (${project.project_status})`); - } catch (error) { - console.log(`โŒ Error parsing date for ${project.project_name}: ${project.finish_date}`); - } -}); \ No newline at end of file diff --git a/check-projects-table.mjs b/check-projects-table.mjs deleted file mode 100644 index 25dfc17..0000000 --- a/check-projects-table.mjs +++ /dev/null @@ -1,5 +0,0 @@ -import db from "./src/lib/db.js"; - -console.log("Current projects table structure:"); -const tableInfo = db.prepare("PRAGMA table_info(projects)").all(); -console.log(JSON.stringify(tableInfo, null, 2)); diff --git a/check-projects.mjs b/check-projects.mjs deleted file mode 100644 index 10823c7..0000000 --- a/check-projects.mjs +++ /dev/null @@ -1,32 +0,0 @@ -import Database from "better-sqlite3"; - -const db = new Database("./data/database.sqlite"); - -// Check table structures first -console.log("Users table structure:"); -const usersSchema = db.prepare("PRAGMA table_info(users)").all(); -console.log(usersSchema); - -console.log("\nProjects table structure:"); -const projectsSchema = db.prepare("PRAGMA table_info(projects)").all(); -console.log(projectsSchema); - -// Check if there are any projects -const projects = db - .prepare( - ` - SELECT p.*, - creator.name as created_by_name, - assignee.name as assigned_to_name - FROM projects p - LEFT JOIN users creator ON p.created_by = creator.id - LEFT JOIN users assignee ON p.assigned_to = assignee.id - LIMIT 5 -` - ) - .all(); - -console.log("\nProjects in database:"); -console.log(JSON.stringify(projects, null, 2)); - -db.close(); diff --git a/check-schema.mjs b/check-schema.mjs deleted file mode 100644 index 038448f..0000000 --- a/check-schema.mjs +++ /dev/null @@ -1,10 +0,0 @@ -import db from "./src/lib/db.js"; - -console.log("Database schema for notes table:"); -console.log(db.prepare("PRAGMA table_info(notes)").all()); - -console.log("\nDatabase schema for project_tasks table:"); -console.log(db.prepare("PRAGMA table_info(project_tasks)").all()); - -console.log("\nSample notes to check is_system column:"); -console.log(db.prepare("SELECT * FROM notes LIMIT 5").all()); diff --git a/check-task-schema.mjs b/check-task-schema.mjs deleted file mode 100644 index 626abe4..0000000 --- a/check-task-schema.mjs +++ /dev/null @@ -1,25 +0,0 @@ -import Database from "better-sqlite3"; - -const db = new Database("./data/database.sqlite"); - -console.log("Project Tasks table structure:"); -const projectTasksSchema = db.prepare("PRAGMA table_info(project_tasks)").all(); -console.table(projectTasksSchema); - -console.log("\nSample project tasks with user tracking:"); -const tasks = db - .prepare( - ` - SELECT pt.*, - creator.name as created_by_name, - assignee.name as assigned_to_name - FROM project_tasks pt - LEFT JOIN users creator ON pt.created_by = creator.id - LEFT JOIN users assignee ON pt.assigned_to = assignee.id - LIMIT 3 -` - ) - .all(); -console.table(tasks); - -db.close(); diff --git a/debug-disabled/comprehensive-polish-map/page.js b/debug-disabled/comprehensive-polish-map/page.js deleted file mode 100644 index 130c7c2..0000000 --- a/debug-disabled/comprehensive-polish-map/page.js +++ /dev/null @@ -1,355 +0,0 @@ -"use client"; - -import { useState } from 'react'; -import dynamic from 'next/dynamic'; - -const ComprehensivePolishMap = dynamic( - () => import('../../components/ui/ComprehensivePolishMap'), - { - ssr: false, - loading: () =>
Loading map...
- } -); - -export default function ComprehensivePolishMapPage() { - const [selectedLocation, setSelectedLocation] = useState('krakow'); - - // Different locations to test the layers - const locations = { - krakow: { - center: [50.0647, 19.9450], - zoom: 14, - name: "Krakรณw", - description: "Historic city center with good cadastral data coverage" - }, - warsaw: { - center: [52.2297, 21.0122], - zoom: 14, - name: "Warszawa", - description: "Capital city with extensive planning data" - }, - gdansk: { - center: [54.3520, 18.6466], - zoom: 14, - name: "Gdaล„sk", - description: "Port city with detailed property boundaries" - }, - wroclaw: { - center: [51.1079, 17.0385], - zoom: 14, - name: "Wrocล‚aw", - description: "University city with good orthophoto coverage" - }, - poznan: { - center: [52.4064, 16.9252], - zoom: 14, - name: "Poznaล„", - description: "Industrial center with road network data" - } - }; - - const currentLocation = locations[selectedLocation]; - - // Test markers for selected location - const testMarkers = [ - { - position: currentLocation.center, - popup: `${currentLocation.name} - ${currentLocation.description}` - } - ]; - - return ( -
-
-

- ๐Ÿ‡ต๐Ÿ‡ฑ Comprehensive Polish Geospatial Data Platform -

- -
-

- All Polish Layers Implementation Complete! ๐ŸŽ‰ -

-

- This comprehensive map includes all layers from your OpenLayers implementation, - converted to work seamlessly with your Leaflet-based React/Next.js project. -

-
-
- Base Layers: -
    -
  • โ€ข Polish Orthophoto (Standard & High Resolution)
  • -
  • โ€ข OpenStreetMap, Google Maps, Esri Satellite
  • -
-
-
- Overlay Layers: -
    -
  • โ€ข Cadastral Data, Spatial Planning
  • -
  • โ€ข LP-Portal Roads, Street Names, Parcels, Surveys
  • -
-
-
-
- - {/* Location Selector */} -
-

- ๐ŸŽฏ Select Test Location: -

-
- {Object.entries(locations).map(([key, location]) => ( - - ))} -
-

- Current: {currentLocation.description} -

-
- - {/* Map Container */} -
-
-

- Interactive Map: {currentLocation.name} -

-

- Use the layer control (top-right) to toggle between base layers and enable overlay layers. - Combine orthophoto with cadastral data for detailed property analysis. -

-
- -
- -
-
- - {/* Layer Information */} -
- {/* Base Layers */} -
-

- ๐Ÿ—บ๏ธ Base Layers -

-
-
- -
- Polish Orthophoto (Standard) -

High-quality aerial imagery from Polish Geoportal

-
-
-
- -
- Polish Orthophoto (High Resolution) -

Ultra-high resolution aerial imagery for detailed analysis

-
-
-
- -
- OpenStreetMap -

Community-driven map data

-
-
-
- -
- Google Maps -

Satellite imagery and road overlay

-
-
-
-
- - {/* Overlay Layers */} -
-

- ๐Ÿ“Š Overlay Layers -

-
- -
- ๐Ÿ“‹ Polish Cadastral Data -

Property boundaries, parcels, and building outlines

-

Opacity: 80% - Semi-transparent overlay

-
-
-
- -
- ๐Ÿ—๏ธ Polish Spatial Planning -

Zoning data and urban planning information

-

Opacity: 70% - Semi-transparent overlay

-
-
-
- -
- ๐Ÿ›ฃ๏ธ LP-Portal Roads -

Detailed road network data

-

Opacity: 90% - Mostly opaque for visibility

-
-
-
- -
- ๐Ÿท๏ธ LP-Portal Street Names -

Street names and road descriptions

-

Opacity: 100% - Fully opaque for readability

-
-
-
- -
- ๐Ÿ“ LP-Portal Parcels & Surveys -

Property parcels and survey markers

-

Opacity: 60-80% - Variable transparency

-
-
-
-
-
- - {/* Transparency Information */} -
-

- ๐ŸŽจ Layer Transparency Handling -

-
-
-

Base Layers (Opaque):

-
-
- Polish Orthophoto - 100% Opaque -
-
- Google Satellite/Roads - 100% Opaque -
-
-
- -
-

Overlay Layers (Transparent):

-
-
- ๐Ÿ“‹ Cadastral Data - 80% Opacity -
-
- ๐Ÿ—๏ธ Spatial Planning - 70% Opacity -
-
- ๐Ÿ›ฃ๏ธ Roads - 90% Opacity -
-
- ๐Ÿท๏ธ Street Names - 100% Opacity -
-
- ๐Ÿ“ Parcels - 60% Opacity -
-
- ๐Ÿ“ Survey Markers - 80% Opacity -
-
-
-
- -
-

- Smart Transparency: Each overlay layer has been optimized with appropriate transparency levels. - Property boundaries are semi-transparent (60-80%) so you can see the underlying imagery, - while text labels are fully opaque (100%) for maximum readability. -

-
-
- - {/* Usage Guide */} -
-

- ๐Ÿ“‹ How to Use This Comprehensive Map -

-
-
-

Basic Navigation:

-
    -
  • โ€ข Use mouse wheel to zoom in/out
  • -
  • โ€ข Click and drag to pan around
  • -
  • โ€ข Use layer control (top-right) to switch layers
  • -
  • โ€ข Select different Polish cities above to test
  • -
-
-
-

Advanced Features:

-
    -
  • โ€ข Combine orthophoto with cadastral overlay
  • -
  • โ€ข Enable multiple overlays simultaneously
  • -
  • โ€ข Use high-resolution orthophoto for detail work
  • -
  • โ€ข Compare with Google/OSM base layers
  • -
-
-
-
- - {/* Technical Implementation */} -
-

- โš™๏ธ Technical Implementation Details -

-
-
-

WMTS Integration:

-
    -
  • โ€ข Proper KVP URL construction
  • -
  • โ€ข EPSG:3857 coordinate system
  • -
  • โ€ข Standard and high-res orthophoto
  • -
  • โ€ข Multiple format support (JPEG/PNG)
  • -
-
-
-

WMS Overlays:

-
    -
  • โ€ข Polish government services
  • -
  • โ€ข LP-Portal municipal data
  • -
  • โ€ข Transparent overlay support
  • -
  • โ€ข Multiple layer combinations
  • -
-
-
-

React/Leaflet:

-
    -
  • โ€ข React-Leaflet component integration
  • -
  • โ€ข Dynamic layer switching
  • -
  • โ€ข Responsive design
  • -
  • โ€ข Performance optimized
  • -
-
-
-
-
-
- ); -} diff --git a/debug-disabled/debug-polish-orthophoto/layout.disabled.js b/debug-disabled/debug-polish-orthophoto/layout.disabled.js deleted file mode 100644 index 6ddd998..0000000 --- a/debug-disabled/debug-polish-orthophoto/layout.disabled.js +++ /dev/null @@ -1,9 +0,0 @@ -// Temporarily disabled debug pages during build -// These pages are for development/testing purposes only -// To re-enable, rename this file to layout.js - -export default function DebugLayout({ children }) { - return children; -} - -export const dynamic = 'force-dynamic'; diff --git a/debug-disabled/debug-polish-orthophoto/page.js b/debug-disabled/debug-polish-orthophoto/page.js deleted file mode 100644 index 71aef92..0000000 --- a/debug-disabled/debug-polish-orthophoto/page.js +++ /dev/null @@ -1,113 +0,0 @@ -"use client"; - -import dynamic from 'next/dynamic'; - -const DebugPolishOrthophotoMap = dynamic( - () => import('../../components/ui/DebugPolishOrthophotoMap'), - { - ssr: false, - loading: () =>
Loading map...
- } -); - -export const dynamicParams = true; - -export default function DebugPolishOrthophotoPage() { - // Test marker in Poland - const testMarkers = [ - { - position: [50.0647, 19.9450], // Krakow - popup: "Krakรณw - Test Location" - } - ]; - - return ( -
-
-

- Debug Polish Geoportal Orthophoto -

- -
-

- Debug Mode Active -

-

- This page tests multiple URL formats for Polish Geoportal orthophoto tiles. - Check the browser console and the debug panel on the map for network request information. -

-
- -
-
-

Debug Map with Multiple Orthophoto Options

-

- Try switching between different Polish orthophoto options using the layer control. - Google layers are included as working references. -

-
- -
- -
-
- -
-

- URL Formats Being Tested: -

-
- Option 1 (WMTS KVP EPSG:3857): - - ?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=ORTO&STYLE=default&TILEMATRIXSET=EPSG:3857&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&FORMAT=image/jpeg - - Standard Web Mercator projection -
- -
- Option 2 (WMTS KVP EPSG:2180): - - ?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=ORTO&STYLE=default&TILEMATRIXSET=EPSG:2180&TILEMATRIX=EPSG:2180:{z}&TILEROW={y}&TILECOL={x}&FORMAT=image/jpeg - - Polish coordinate system -
- -
- Option 3 (Alternative TILEMATRIXSET): - - ?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=ORTO&STYLE=default&TILEMATRIXSET=GoogleMapsCompatible&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&FORMAT=image/jpeg - - Google Maps compatible matrix -
- -
- Option 4 (PNG format): - - ?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=ORTO&STYLE=default&TILEMATRIXSET=EPSG:3857&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&FORMAT=image/png - - PNG format instead of JPEG -
-
-
- -
-

- Debug Instructions: -

-
    -
  1. 1. Open browser Developer Tools (F12) and go to Network tab
  2. -
  3. 2. Switch between different Polish orthophoto options in the layer control
  4. -
  5. 3. Look for requests to geoportal.gov.pl in the Network tab
  6. -
  7. 4. Check the debug panel on the map for request/response info
  8. -
  9. 5. Note which options return 200 OK vs 404/403 errors
  10. -
  11. 6. Compare with working Google layers
  12. -
-
-
-
- ); -} \ No newline at end of file diff --git a/debug-disabled/test-improved-wmts/page.js b/debug-disabled/test-improved-wmts/page.js deleted file mode 100644 index fe336ca..0000000 --- a/debug-disabled/test-improved-wmts/page.js +++ /dev/null @@ -1,107 +0,0 @@ -"use client"; - -import dynamic from 'next/dynamic'; - -const ImprovedPolishOrthophotoMap = dynamic( - () => import('../../components/ui/ImprovedPolishOrthophotoMap'), - { - ssr: false, - loading: () =>
Loading map...
- } -); - -export default function ImprovedPolishOrthophotoPage() { - const testMarkers = [ - { - position: [50.0647, 19.9450], // Krakow - popup: "Krakรณw - Testing WMTS" - } - ]; - - return ( -
-
-

- Improved Polish WMTS Implementation -

- -
-

- Custom WMTS Layer Implementation -

-

- This version uses a custom WMTS layer that properly constructs KVP URLs based on the GetCapabilities response. - Check the debug panel on the map to see the actual requests being made. -

-
- -
-
-

Custom WMTS Layer with Proper KVP URLs

-

- This implementation builds proper WMTS GetTile requests with all required parameters. - Monitor the debug panel and browser network tab for request details. -

-
- -
- -
-
- -
-

- WMTS Parameters Being Tested: -

-
-
- Tile Matrix Sets Available: -
    -
  • โ€ข EPSG:3857 (Web Mercator)
  • -
  • โ€ข EPSG:4326 (WGS84)
  • -
  • โ€ข EPSG:2180 (Polish National Grid)
  • -
-
- -
- Formats Available: -
    -
  • โ€ข image/jpeg (default)
  • -
  • โ€ข image/png
  • -
-
-
-
- -
-

- Testing Instructions: -

-
    -
  1. 1. Open Browser Developer Tools (F12) โ†’ Network tab
  2. -
  3. 2. Filter by "geoportal.gov.pl" to see WMTS requests
  4. -
  5. 3. Switch between different Polish WMTS options
  6. -
  7. 4. Check if requests return 200 OK or error codes
  8. -
  9. 5. Compare with Google Satellite (known working)
  10. -
  11. 6. Monitor the debug panel for request URLs
  12. -
-
- -
-

- Expected Behavior: -

-

- If the Polish orthophoto tiles appear, you should see aerial imagery of Poland. - If they don't load, check the network requests - they should show proper WMTS GetTile URLs - with all required parameters (SERVICE, REQUEST, LAYER, TILEMATRIXSET, etc.). -

-
-
-
- ); -} diff --git a/debug-disabled/test-polish-map/page.js b/debug-disabled/test-polish-map/page.js deleted file mode 100644 index df033d9..0000000 --- a/debug-disabled/test-polish-map/page.js +++ /dev/null @@ -1,217 +0,0 @@ -"use client"; - -import { useState } from 'react'; -import dynamic from 'next/dynamic'; - -const PolishOrthophotoMap = dynamic( - () => import('../../components/ui/PolishOrthophotoMap'), - { - ssr: false, - loading: () =>
Loading map...
- } -); - -const AdvancedPolishOrthophotoMap = dynamic( - () => import('../../components/ui/AdvancedPolishOrthophotoMap'), - { - ssr: false, - loading: () =>
Loading map...
- } -); - -export default function PolishOrthophotoTestPage() { - const [activeMap, setActiveMap] = useState('basic'); - - // Test markers - various locations in Poland - const testMarkers = [ - { - position: [50.0647, 19.9450], // Krakow - popup: "Krakรณw - Main Market Square" - }, - { - position: [52.2297, 21.0122], // Warsaw - popup: "Warszawa - Palace of Culture and Science" - }, - { - position: [54.3520, 18.6466], // Gdansk - popup: "Gdaล„sk - Old Town" - } - ]; - - return ( -
-
-

- Polish Geoportal Orthophoto Integration -

- - {/* Map Type Selector */} -
-

- Choose Map Implementation: -

-
- - -
-
- - {/* Map Container */} -
-
-

- {activeMap === 'basic' - ? 'Basic Polish Orthophoto Map' - : 'Advanced Polish Orthophoto with WMS Overlays' - } -

-

- {activeMap === 'basic' - ? 'Demonstrates working Polish Geoportal orthophoto tiles with multiple base layer options.' - : 'Advanced version includes Polish cadastral data (dziaล‚ki) and spatial planning (MPZT) as overlay layers.' - } -

-
- -
- {activeMap === 'basic' ? ( - - ) : ( - - )} -
-
- - {/* Features Overview */} -
-
-

- Basic Map Features: -

-
    -
  • - - Polish Geoportal Orthophoto (Working) -
  • -
  • - - OpenStreetMap base layer -
  • -
  • - - Google Satellite imagery -
  • -
  • - - Google Roads overlay -
  • -
  • - - Esri World Imagery -
  • -
-
- -
-

- Advanced Map Features: -

-
    -
  • - - Standard & High Resolution Orthophoto -
  • -
  • - - Polish Cadastral Data (WMS) -
  • -
  • - - Spatial Planning Data (MPZT) -
  • -
  • - - Overlay layer support -
  • -
  • - - Multiple base layers -
  • -
-
-
- - {/* Technical Implementation Details */} -
-

- Technical Implementation: -

-
-
-

Key Improvements:

-
    -
  • โ€ข Uses REST tile service instead of WMTS for better compatibility
  • -
  • โ€ข Proper tile size (512px) with zoomOffset=-1
  • -
  • โ€ข proj4 integration for EPSG:2180 coordinate system
  • -
  • โ€ข Multiple fallback layers for reliability
  • -
  • โ€ข WMS overlay support for cadastral data
  • -
-
-
-

Based on OpenLayers Code:

-
    -
  • โ€ข Converted from OpenLayers to Leaflet implementation
  • -
  • โ€ข Maintains same layer structure and URLs
  • -
  • โ€ข Includes Polish projection definitions
  • -
  • โ€ข Compatible with existing React/Next.js setup
  • -
  • โ€ข Extensible for additional WMS services
  • -
-
-
-
- - {/* Usage Instructions */} -
-

- How to Use: -

-
-

1. Use the layer control (top-right) to switch between base layers

-

2. In advanced mode, enable overlay layers for cadastral/planning data

-

3. Click on markers to see location information

-

4. Zoom in to see high-resolution orthophoto details

-

5. Combine orthophoto with cadastral overlay for property boundaries

-
-
-
-
- ); -} diff --git a/debug-disabled/test-polish-orthophoto/page.js b/debug-disabled/test-polish-orthophoto/page.js deleted file mode 100644 index fecc41a..0000000 --- a/debug-disabled/test-polish-orthophoto/page.js +++ /dev/null @@ -1,106 +0,0 @@ -"use client"; - -import dynamic from 'next/dynamic'; - -const PolishOrthophotoMap = dynamic( - () => import('../../components/ui/PolishOrthophotoMap'), - { - ssr: false, - loading: () =>
Loading map...
- } -); - -export default function TestPolishOrthophotoPage() { - // Test markers - various locations in Poland - const testMarkers = [ - { - position: [50.0647, 19.9450], // Krakow - popup: "Krakรณw - Main Market Square" - }, - { - position: [52.2297, 21.0122], // Warsaw - popup: "Warszawa - Palace of Culture and Science" - }, - { - position: [54.3520, 18.6466], // Gdansk - popup: "Gdaล„sk - Old Town" - } - ]; - - return ( -
-
-

- Polish Geoportal Orthophoto Map Test -

- -
-
-

Interactive Map with Polish Orthophoto

-

- This map demonstrates working Polish Geoportal orthophoto tiles. - Use the layer control (top-right) to switch between different map layers. -

-
- -
- -
-
- -
-

- Map Layers Available: -

-
    -
  • - - Polish Geoportal Orthophoto: High-resolution aerial imagery from Polish Geoportal -
  • -
  • - - OpenStreetMap: Standard OpenStreetMap tiles -
  • -
  • - - Google Satellite: Google satellite imagery -
  • -
  • - - Google Roads: Google road overlay -
  • -
  • - - Esri Satellite: Esri world imagery -
  • -
-
- -
-

- Implementation Notes: -

-
-

- โ€ข The Polish Geoportal orthophoto uses REST tile service instead of WMTS for better compatibility -

-

- โ€ข Tile size is set to 512px with zoomOffset=-1 for proper tile alignment -

-

- โ€ข proj4 library is included for coordinate system transformations (EPSG:2180) -

-

- โ€ข Multiple fallback layers are provided for comparison and reliability -

-
-
-
-
- ); -} diff --git a/debug-dropdown.js b/debug-dropdown.js deleted file mode 100644 index 08a80c2..0000000 --- a/debug-dropdown.js +++ /dev/null @@ -1,11 +0,0 @@ -// Debug file to test dropdown functionality -console.log("Testing dropdown components..."); - -// Simple test to check if components are rendering -const testTask = { - id: 1, - status: "pending", - task_name: "Test Task", -}; - -console.log("Test task:", testTask); diff --git a/debug-task-insert.mjs b/debug-task-insert.mjs deleted file mode 100644 index edc8666..0000000 --- a/debug-task-insert.mjs +++ /dev/null @@ -1,49 +0,0 @@ -import Database from "better-sqlite3"; - -const db = new Database("./data/database.sqlite"); - -console.log("Project Tasks table columns:"); -const projectTasksSchema = db.prepare("PRAGMA table_info(project_tasks)").all(); -projectTasksSchema.forEach((col) => { - console.log( - `${col.name}: ${col.type} (${col.notnull ? "NOT NULL" : "NULL"})` - ); -}); - -console.log("\nChecking if created_at and updated_at columns exist..."); -const hasCreatedAt = projectTasksSchema.some( - (col) => col.name === "created_at" -); -const hasUpdatedAt = projectTasksSchema.some( - (col) => col.name === "updated_at" -); -console.log("created_at exists:", hasCreatedAt); -console.log("updated_at exists:", hasUpdatedAt); - -// Let's try a simple insert to see what happens -console.log("\nTesting manual insert..."); -try { - const result = db - .prepare( - ` - INSERT INTO project_tasks ( - project_id, task_template_id, status, priority, - created_by, assigned_to, created_at, updated_at - ) - VALUES (?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP) - ` - ) - .run(1, 1, "pending", "normal", "test-user", "test-user"); - - console.log("Insert successful, ID:", result.lastInsertRowid); - - // Clean up - db.prepare("DELETE FROM project_tasks WHERE id = ?").run( - result.lastInsertRowid - ); - console.log("Test record cleaned up"); -} catch (error) { - console.error("Insert failed:", error.message); -} - -db.close(); diff --git a/fix-notes-columns.mjs b/fix-notes-columns.mjs deleted file mode 100644 index 284c8ac..0000000 --- a/fix-notes-columns.mjs +++ /dev/null @@ -1,60 +0,0 @@ -import Database from "better-sqlite3"; - -const db = new Database("./data/database.sqlite"); - -console.log("Adding user tracking columns to notes table...\n"); - -try { - console.log("Adding created_by column..."); - db.exec(`ALTER TABLE notes ADD COLUMN created_by TEXT;`); - console.log("โœ“ created_by column added"); -} catch (e) { - console.log("created_by column already exists or error:", e.message); -} - -try { - console.log("Adding is_system column..."); - db.exec(`ALTER TABLE notes ADD COLUMN is_system INTEGER DEFAULT 0;`); - console.log("โœ“ is_system column added"); -} catch (e) { - console.log("is_system column already exists or error:", e.message); -} - -console.log("\nVerifying columns were added..."); -const schema = db.prepare("PRAGMA table_info(notes)").all(); -const hasCreatedBy = schema.some((col) => col.name === "created_by"); -const hasIsSystem = schema.some((col) => col.name === "is_system"); - -console.log("created_by exists:", hasCreatedBy); -console.log("is_system exists:", hasIsSystem); - -if (hasCreatedBy && hasIsSystem) { - console.log("\nโœ… All columns are now present!"); - - // Test a manual insert - console.log("\nTesting manual note insert..."); - try { - const result = db - .prepare( - ` - INSERT INTO notes (project_id, note, created_by, is_system, note_date) - VALUES (?, ?, ?, ?, CURRENT_TIMESTAMP) - ` - ) - .run(1, "Test note with user tracking", "test-user-id", 0); - - console.log("Insert successful, ID:", result.lastInsertRowid); - - // Clean up - db.prepare("DELETE FROM notes WHERE note_id = ?").run( - result.lastInsertRowid - ); - console.log("Test record cleaned up"); - } catch (error) { - console.error("Insert failed:", error.message); - } -} else { - console.log("\nโŒ Some columns are still missing"); -} - -db.close(); diff --git a/fix-task-columns.mjs b/fix-task-columns.mjs deleted file mode 100644 index cbb4c7a..0000000 --- a/fix-task-columns.mjs +++ /dev/null @@ -1,37 +0,0 @@ -import Database from "better-sqlite3"; - -const db = new Database("./data/database.sqlite"); - -console.log("Adding missing columns to project_tasks table...\n"); - -try { - console.log("Adding created_at column..."); - db.exec(`ALTER TABLE project_tasks ADD COLUMN created_at TEXT;`); - console.log("โœ“ created_at column added"); -} catch (e) { - console.log("created_at column already exists or error:", e.message); -} - -try { - console.log("Adding updated_at column..."); - db.exec(`ALTER TABLE project_tasks ADD COLUMN updated_at TEXT;`); - console.log("โœ“ updated_at column added"); -} catch (e) { - console.log("updated_at column already exists or error:", e.message); -} - -console.log("\nVerifying columns were added..."); -const schema = db.prepare("PRAGMA table_info(project_tasks)").all(); -const hasCreatedAt = schema.some((col) => col.name === "created_at"); -const hasUpdatedAt = schema.some((col) => col.name === "updated_at"); - -console.log("created_at exists:", hasCreatedAt); -console.log("updated_at exists:", hasUpdatedAt); - -if (hasCreatedAt && hasUpdatedAt) { - console.log("\nโœ… All columns are now present!"); -} else { - console.log("\nโŒ Some columns are still missing"); -} - -db.close(); diff --git a/geoportal-capabilities.xml b/geoportal-capabilities.xml deleted file mode 100644 index 3b86ec4..0000000 --- a/geoportal-capabilities.xml +++ /dev/null @@ -1,1143 +0,0 @@ -๏ปฟ - - - - - - - - Usล‚uga przeglฤ…dania ortofotomap dla obszaru Polski. Profil kafelkowany (WMTS) - Usล‚uga przeglฤ…dania ortofotomap dla obszaru Polski. Dane udostฤ™pniane za pomocฤ… tej usล‚ugi stanowiฤ… ortofotomapฤ™ wykonanฤ… ze zdjฤ™ฤ‡ lotniczych. Usล‚uga wykorzystuje interfejs WMTS OGC w wersji 1.0.0. - - WMTS - Tiled - Web Map Tile Service - Usล‚uga przeglฤ…dania - Aerial ortoimagery - Aerial photography - Dane referencyjne - Fotografia terenu - Land image - Land photography - Obraz terenu - Orthoimagery - Ortofotogram - Ortofotomapa lotnicza - Ortofotomapa - Raster - Rastry - Referential data - Zdjฤ™cie lotnicze - Sporzฤ…dzanie ortoobrazรณw - - - OGC WMTS - 1.0.0 - Korzystanie z usล‚ugi danych przestrzennych oznacza akceptacjฤ™ bez ograniczeล„ i zastrzeลผeล„ Regulaminu dostฤ™pnego na stronie internetowej Geoportalu http://www.geoportal.gov.pl/ - brak ograniczeล„ - - - Gล‚รณwny Urzฤ…d Geodezji i Kartografii - - - Dziaล‚ Geoportalu - - - +48225631414 - - - Wspรณlna 2 - Warszawa - mazowieckie - 00-926 - Polska - geoportal@geoportal.gov.pl - - - - - - - - - - - - KVP - - - - - - - - - - - - - KVP - - - - - - - - - - - - - KVP - - - - - - - - - https://mapy.geoportal.gov.pl/wss/service/PZGIK/ORTO/WMTS/StandardResolution?REQUEST=GetCapabilities&SERVICE=WMTS - text/xml - - service - - 2012-10-24 - - - - ROZPORZฤ„DZENIE KOMISJI (UE) NR 1089/2010 z dnia 23 listopada 2010 r. w sprawie wykonania dyrektywy 2007/2/WE Parlamentu Europejskiego i Rady w zakresie interoperacyjnoล›ci zbiorรณw i usล‚ug danych przestrzennych - 2010-12-08 - OJ:L:2010:323:0011:0102:PL:PDF - - http://eur-lex.europa.eu/LexUriServ/LexUriServ.do?uri=OJ:L:2010:323:0011:0102:PL:PDF - application/pdf - - - notConformant - - - Gล‚รณwny Urzฤ…d Geodezji i Kartografii - geoportal@geoportal.gov.pl - - 2012-10-24 - view - - infoMapAccessService - - - - GEMET - INSPIRE themes - 2008-06-01 - - Uลผytkowanie terenu - - - WMTS - - - Tiled - - - View service - - - Web Map Tile Service - - - Usล‚uga przeglฤ…dania - - - Aerial ortoimagery - - - Aerial photography - - - Dane referencyjne - - - Fotografia terenu - - - Land image - - - Land photography - - - Obraz terenu - - - Orthoimagery - - - Ortofotogram - - - Ortofotomapa lotnicza - - - Ortofotomapa - - - Raster - - - Rastry - - - Referential data - - - Zdjฤ™cie lotnicze - - - Sporzฤ…dzanie ortoobrazรณw - - - - pol - - - - pol - - - https://mapy.geoportal.gov.pl/wss/service/CSWINSP/guest/CSWStartup?SERVICE=CSW&REQUEST=GetRecordById&VERSION=2.0.2&ID=8b61894c-5e89-4626-8353-9f00b302d2eb&OUTPUTFORMAT=application/xml&OUTPUTSCHEMA=http://www.isotc211.org/2005/gmd&ELEMENTSETNAME=full - text/xml - - - - - - ORTOFOTOMAPA - Warstwa prezentujฤ…ca ortofotomapฤ™ utworzonฤ… ze zdjฤ™ฤ‡ lotniczych. - - Ortofotomapa - - - 13.800 48.800 - 24.400 55.000 - - - ORTOFOTOMAPA - - - image/jpeg - text/html - text/xml; subtype=gml/3.2 - application/gml+xml; version=3.2 - - - -EPSG:2180 - - -EPSG:2180:0 -0 -0 -0 -0 - - -EPSG:2180:1 -0 -0 -0 -0 - - -EPSG:2180:2 -0 -0 -0 -0 - - -EPSG:2180:3 -0 -1 -0 -1 - - -EPSG:2180:4 -0 -2 -0 -2 - - -EPSG:2180:5 -0 -5 -0 -5 - - -EPSG:2180:6 -1 -10 -0 -11 - - -EPSG:2180:7 -2 -21 -1 -22 - - -EPSG:2180:8 -5 -53 -4 -56 - - -EPSG:2180:9 -10 -106 -9 -113 - - -EPSG:2180:10 -20 -213 -19 -226 - - -EPSG:2180:11 -51 -532 -49 -566 - - -EPSG:2180:12 -103 -1065 -98 -1132 - - -EPSG:2180:13 -258 -2663 -246 -2830 - - -EPSG:2180:14 -516 -5327 -492 -5661 - - -EPSG:2180:15 -1033 -10655 -984 -11322 - - -EPSG:2180:16 -2066 -21311 -1969 -22644 - - - - -EPSG:4326 - - -EPSG:4326:0 -0 -0 -0 -0 - - -EPSG:4326:1 -0 -0 -0 -0 - - -EPSG:4326:2 -0 -0 -0 -1 - - -EPSG:4326:3 -0 -1 -0 -2 - - -EPSG:4326:4 -0 -2 -0 -5 - - -EPSG:4326:5 -0 -5 -1 -10 - - -EPSG:4326:6 -1 -11 -2 -20 - - -EPSG:4326:7 -3 -23 -5 -41 - - -EPSG:4326:8 -9 -58 -14 -104 - - -EPSG:4326:9 -18 -116 -29 -208 - - -EPSG:4326:10 -36 -232 -59 -417 - - -EPSG:4326:11 -91 -581 -148 -1042 - - -EPSG:4326:12 -183 -1163 -297 -2085 - - -EPSG:4326:13 -458 -2908 -744 -5214 - - -EPSG:4326:14 -916 -5817 -1489 -10428 - - -EPSG:4326:15 -1832 -11634 -2979 -20857 - - -EPSG:4326:16 -3665 -23269 -5959 -41714 - - - - -EPSG:3857 - - -EPSG:3857:0 -0 -0 -0 -0 - - -EPSG:3857:1 -0 -0 -1 -1 - - -EPSG:3857:2 -1 -1 -2 -2 - - -EPSG:3857:3 -2 -2 -4 -4 - - -EPSG:3857:4 -5 -5 -8 -9 - - -EPSG:3857:5 -10 -11 -17 -18 - - -EPSG:3857:6 -20 -22 -34 -36 - - -EPSG:3857:7 -40 -44 -68 -72 - - -EPSG:3857:8 -81 -88 -137 -145 - - -EPSG:3857:9 -162 -176 -275 -291 - - -EPSG:3857:10 -324 -352 -551 -582 - - -EPSG:3857:11 -648 -704 -1102 -1164 - - -EPSG:3857:12 -1297 -1408 -2205 -2329 - - -EPSG:3857:13 -2595 -2816 -4410 -4658 - - -EPSG:3857:14 -5191 -5632 -8820 -9316 - - -EPSG:3857:15 -10382 -11265 -17641 -18632 - - -EPSG:3857:16 -20765 -22530 -35282 -37265 - - -EPSG:3857:17 -41531 -45061 -70565 -74530 - - -EPSG:3857:18 -83063 -90122 -141131 -149061 - - -EPSG:3857:19 -166126 -180245 -282263 -298123 - - - - - -EPSG:2180 -urn:ogc:def:crs:EPSG::2180 - -EPSG:2180:0 -3.0238155714285716E7 -850000.0 100000.0 -512 -512 -1 -1 - - -EPSG:2180:1 -1.5119077857142858E7 -850000.0 100000.0 -512 -512 -1 -1 - - -EPSG:2180:2 -7559538.928571429 -850000.0 100000.0 -512 -512 -1 -1 - - -EPSG:2180:3 -3779769.4642857146 -850000.0 100000.0 -512 -512 -2 -2 - - -EPSG:2180:4 -1889884.7321428573 -850000.0 100000.0 -512 -512 -3 -3 - - -EPSG:2180:5 -944942.3660714286 -850000.0 100000.0 -512 -512 -6 -6 - - -EPSG:2180:6 -472471.1830357143 -850000.0 100000.0 -512 -512 -12 -11 - - -EPSG:2180:7 -236235.59151785716 -850000.0 100000.0 -512 -512 -23 -22 - - -EPSG:2180:8 -94494.23660714286 -850000.0 100000.0 -512 -512 -57 -54 - - -EPSG:2180:9 -47247.11830357143 -850000.0 100000.0 -512 -512 -114 -107 - - -EPSG:2180:10 -23623.559151785714 -850000.0 100000.0 -512 -512 -227 -214 - - -EPSG:2180:11 -9449.423660714287 -850000.0 100000.0 -512 -512 -567 -533 - - -EPSG:2180:12 -4724.711830357143 -850000.0 100000.0 -512 -512 -1133 -1066 - - -EPSG:2180:13 -1889.8847321428573 -850000.0 100000.0 -512 -512 -2831 -2664 - - -EPSG:2180:14 -944.9423660714286 -850000.0 100000.0 -512 -512 -5662 -5328 - - -EPSG:2180:15 -472.4711830357143 -850000.0 100000.0 -512 -512 -11323 -10656 - - -EPSG:2180:16 -236.23559151785716 -850000.0 100000.0 -512 -512 -22645 -21312 - - - -EPSG:4326 -urn:ogc:def:crs:EPSG::4326 - -EPSG:4326:0 -3.0238155714402866E7 -56.0 12.0 -512 -512 -1 -1 - - -EPSG:4326:1 -1.5119077857201433E7 -56.0 12.0 -512 -512 -1 -1 - - -EPSG:4326:2 -7559538.928600716 -56.0 12.0 -512 -512 -2 -1 - - -EPSG:4326:3 -3779769.464300358 -56.0 12.0 -512 -512 -3 -2 - - -EPSG:4326:4 -1889884.732150179 -56.0 12.0 -512 -512 -6 -3 - - -EPSG:4326:5 -944942.3660750896 -56.0 12.0 -512 -512 -11 -6 - - -EPSG:4326:6 -472471.1830375448 -56.0 12.0 -512 -512 -21 -12 - - -EPSG:4326:7 -236235.5915187724 -56.0 12.0 -512 -512 -42 -24 - - -EPSG:4326:8 -94494.23660750895 -56.0 12.0 -512 -512 -105 -59 - - -EPSG:4326:9 -47247.118303754476 -56.0 12.0 -512 -512 -209 -117 - - -EPSG:4326:10 -23623.559151877238 -56.0 12.0 -512 -512 -418 -233 - - -EPSG:4326:11 -9449.423660750896 -56.0 12.0 -512 -512 -1043 -582 - - -EPSG:4326:12 -4724.711830375448 -56.0 12.0 -512 -512 -2086 -1164 - - -EPSG:4326:13 -1889.884732150179 -56.0 12.0 -512 -512 -5215 -2909 - - -EPSG:4326:14 -944.9423660750895 -56.0 12.0 -512 -512 -10429 -5818 - - -EPSG:4326:15 -472.47118303754473 -56.0 12.0 -512 -512 -20858 -11635 - - -EPSG:4326:16 -236.23559151877237 -56.0 12.0 -512 -512 -41715 -23270 - - - -EPSG:3857 -urn:ogc:def:crs:EPSG::3857 - -EPSG:3857:0 -5.590822640263356E8 --2.0037508342787E7 2.0037508342787E7 -256 -256 -1 -1 - - -EPSG:3857:1 -2.795411320131673E8 --2.0037508342787E7 2.0037508342787E7 -256 -256 -2 -1 - - -EPSG:3857:2 -1.397705660065841E8 --2.0037508342787E7 2.0037508342787E7 -256 -256 -3 -2 - - -EPSG:3857:3 -6.988528300329159E7 --2.0037508342787E7 2.0037508342787E7 -256 -256 -5 -3 - - -EPSG:3857:4 -3.4942641501645796E7 --2.0037508342787E7 2.0037508342787E7 -256 -256 -10 -6 - - -EPSG:3857:5 -1.7471320750822898E7 --2.0037508342787E7 2.0037508342787E7 -256 -256 -19 -12 - - -EPSG:3857:6 -8735660.375411449 --2.0037508342787E7 2.0037508342787E7 -256 -256 -37 -23 - - -EPSG:3857:7 -4367830.1877057245 --2.0037508342787E7 2.0037508342787E7 -256 -256 -73 -45 - - -EPSG:3857:8 -2183915.093853335 --2.0037508342787E7 2.0037508342787E7 -256 -256 -146 -89 - - -EPSG:3857:9 -1091957.5469261948 --2.0037508342787E7 2.0037508342787E7 -256 -256 -292 -177 - - -EPSG:3857:10 -545978.7734635699 --2.0037508342787E7 2.0037508342787E7 -256 -256 -583 -353 - - -EPSG:3857:11 -272989.38673131244 --2.0037508342787E7 2.0037508342787E7 -256 -256 -1165 -705 - - -EPSG:3857:12 -136494.69336565622 --2.0037508342787E7 2.0037508342787E7 -256 -256 -2330 -1409 - - -EPSG:3857:13 -68247.34668282811 --2.0037508342787E7 2.0037508342787E7 -256 -256 -4659 -2817 - - -EPSG:3857:14 -34123.673341414054 --2.0037508342787E7 2.0037508342787E7 -256 -256 -9317 -5633 - - -EPSG:3857:15 -17061.8366711795 --2.0037508342787E7 2.0037508342787E7 -256 -256 -18633 -11266 - - -EPSG:3857:16 -8530.91833558975 --2.0037508342787E7 2.0037508342787E7 -256 -256 -37266 -22531 - - -EPSG:3857:17 -4265.459167322403 --2.0037508342787E7 2.0037508342787E7 -256 -256 -74531 -45062 - - -EPSG:3857:18 -2132.729584133673 --2.0037508342787E7 2.0037508342787E7 -256 -256 -149062 -90123 - - -EPSG:3857:19 -1066.3647915943654 --2.0037508342787E7 2.0037508342787E7 -256 -256 -298124 -180246 - - - - - - diff --git a/migrate-add-completion-date.mjs b/migrate-add-completion-date.mjs deleted file mode 100644 index aeef859..0000000 --- a/migrate-add-completion-date.mjs +++ /dev/null @@ -1,29 +0,0 @@ -import db from "./src/lib/db.js"; - -export default function migrateAddCompletionDate() { - try { - // First, check if actual_completion_date exists and rename it to completion_date - const columns = db.prepare("PRAGMA table_info(projects)").all(); - const hasActualCompletionDate = columns.some(col => col.name === 'actual_completion_date'); - const hasCompletionDate = columns.some(col => col.name === 'completion_date'); - - if (hasActualCompletionDate && !hasCompletionDate) { - // Rename the column - db.exec(` - ALTER TABLE projects RENAME COLUMN actual_completion_date TO completion_date; - `); - console.log("Migration completed: Renamed actual_completion_date to completion_date"); - } else if (!hasActualCompletionDate && !hasCompletionDate) { - // Add the column if it doesn't exist - db.exec(` - ALTER TABLE projects ADD COLUMN completion_date TEXT; - `); - console.log("Migration completed: Added completion_date column to projects table"); - } else if (hasCompletionDate) { - console.log("Migration skipped: completion_date column already exists"); - } - } catch (error) { - console.error("Migration failed:", error); - throw error; - } -} \ No newline at end of file diff --git a/migrate-add-docx-templates-table.mjs b/migrate-add-docx-templates-table.mjs deleted file mode 100644 index 6315bbb..0000000 --- a/migrate-add-docx-templates-table.mjs +++ /dev/null @@ -1,38 +0,0 @@ -import db from "./src/lib/db.js"; - -// Migration to add docx_templates table -const migration = () => { - console.log("Running migration: add-docx-templates-table"); - - try { - db.exec(` - -- Table: docx_templates - CREATE TABLE IF NOT EXISTS docx_templates ( - template_id INTEGER PRIMARY KEY AUTOINCREMENT, - template_name TEXT NOT NULL, - description TEXT, - original_filename TEXT NOT NULL, - stored_filename TEXT NOT NULL, - file_path TEXT NOT NULL, - file_size INTEGER NOT NULL, - mime_type TEXT NOT NULL, - is_active INTEGER DEFAULT 1, - created_at TEXT DEFAULT CURRENT_TIMESTAMP, - created_by TEXT, - updated_at TEXT DEFAULT CURRENT_TIMESTAMP, - FOREIGN KEY (created_by) REFERENCES users(id) - ); - - -- Indexes for templates - CREATE INDEX IF NOT EXISTS idx_docx_templates_active ON docx_templates(is_active); - CREATE INDEX IF NOT EXISTS idx_docx_templates_created_by ON docx_templates(created_by); - `); - - console.log("Migration completed successfully"); - } catch (error) { - console.error("Migration failed:", error); - throw error; - } -}; - -migration(); \ No newline at end of file diff --git a/migrate-add-edited-at-to-notes.mjs b/migrate-add-edited-at-to-notes.mjs deleted file mode 100644 index bdeb495..0000000 --- a/migrate-add-edited-at-to-notes.mjs +++ /dev/null @@ -1,27 +0,0 @@ -import db from "./src/lib/db.js"; - -export default function migrateAddEditedAtToNotes() { - try { - // Check if edited_at column already exists - const columns = db.prepare("PRAGMA table_info(notes)").all(); - const hasEditedAt = columns.some(col => col.name === 'edited_at'); - - if (!hasEditedAt) { - // Add the edited_at column - db.exec(` - ALTER TABLE notes ADD COLUMN edited_at TEXT; - `); - console.log("Migration completed: Added edited_at column to notes table"); - } else { - console.log("Migration skipped: edited_at column already exists"); - } - } catch (error) { - console.error("Migration failed:", error); - throw error; - } -} - -// Run the migration if this file is executed directly -if (import.meta.url === `file://${process.argv[1]}`) { - migrateAddEditedAtToNotes(); -} \ No newline at end of file diff --git a/migrate-add-initial-column.mjs b/migrate-add-initial-column.mjs deleted file mode 100644 index 7d53c5c..0000000 --- a/migrate-add-initial-column.mjs +++ /dev/null @@ -1,43 +0,0 @@ -import Database from "better-sqlite3"; - -// Migration script to add 'initial' column to users table -// Run this on your live server to apply the database changes - -const dbPath = process.argv[2] || "./data/database.sqlite"; // Allow custom path via command line - -console.log(`Applying migration to database: ${dbPath}`); - -try { - const db = new Database(dbPath); - - // Check if initial column already exists - const schema = db.prepare("PRAGMA table_info(users)").all(); - const hasInitialColumn = schema.some(column => column.name === 'initial'); - - if (hasInitialColumn) { - console.log("โœ… Initial column already exists in users table"); - } else { - // Add the initial column - db.prepare("ALTER TABLE users ADD COLUMN initial TEXT").run(); - console.log("โœ… Added 'initial' column to users table"); - } - - // Verify the column was added - const updatedSchema = db.prepare("PRAGMA table_info(users)").all(); - const initialColumn = updatedSchema.find(column => column.name === 'initial'); - - if (initialColumn) { - console.log("โœ… Migration completed successfully"); - console.log(`Column details: ${JSON.stringify(initialColumn, null, 2)}`); - } else { - console.error("โŒ Migration failed - initial column not found"); - process.exit(1); - } - - db.close(); - console.log("Database connection closed"); - -} catch (error) { - console.error("โŒ Migration failed:", error.message); - process.exit(1); -} \ No newline at end of file diff --git a/migrate-add-settings-table.mjs b/migrate-add-settings-table.mjs deleted file mode 100644 index e602469..0000000 --- a/migrate-add-settings-table.mjs +++ /dev/null @@ -1,25 +0,0 @@ -import db from "./src/lib/db.js"; - -console.log("Adding settings table..."); - -try { - db.exec(` - CREATE TABLE IF NOT EXISTS settings ( - key TEXT PRIMARY KEY, - value TEXT NOT NULL, - description TEXT, - updated_at TEXT DEFAULT CURRENT_TIMESTAMP, - updated_by TEXT, - FOREIGN KEY (updated_by) REFERENCES users(id) - ); - `); - - db.exec(` - INSERT OR IGNORE INTO settings (key, value, description) VALUES - ('backup_notification_user_id', '', 'User ID to receive backup completion notifications'); - `); - - console.log("โœ… Settings table created successfully"); -} catch (error) { - console.error("Error creating settings table:", error); -} \ No newline at end of file diff --git a/migrate-add-team-lead-role.mjs b/migrate-add-team-lead-role.mjs deleted file mode 100644 index 215a8e5..0000000 --- a/migrate-add-team-lead-role.mjs +++ /dev/null @@ -1,75 +0,0 @@ -import db from './src/lib/db.js'; - -console.log('Starting migration to add team_lead role to users table constraint...'); - -try { - // Disable foreign key constraints temporarily - db.pragma('foreign_keys = OFF'); - console.log('Disabled foreign key constraints'); - - // Since SQLite doesn't support modifying CHECK constraints directly, - // we need to recreate the table with the new constraint - - // First, create a backup table with current data - db.exec('CREATE TABLE users_backup AS SELECT * FROM users'); - console.log('Created backup table'); - - // Drop the original table - db.exec('DROP TABLE users'); - console.log('Dropped original table'); - - // Recreate the table with the updated constraint - db.exec(` - CREATE TABLE users ( - id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(16)))), - name TEXT NOT NULL, - username TEXT UNIQUE NOT NULL, - password_hash TEXT NOT NULL, - role TEXT CHECK(role IN ('admin', 'team_lead', 'project_manager', 'user', 'read_only')) DEFAULT 'user', - created_at TEXT DEFAULT CURRENT_TIMESTAMP, - updated_at TEXT DEFAULT CURRENT_TIMESTAMP, - is_active INTEGER DEFAULT 1, - last_login TEXT, - failed_login_attempts INTEGER DEFAULT 0, - locked_until TEXT, - can_be_assigned INTEGER DEFAULT 1, - initial TEXT - ) - `); - console.log('Created new table with updated constraint'); - - // Copy data back from backup - db.exec(` - INSERT INTO users ( - id, name, username, password_hash, role, created_at, updated_at, - is_active, last_login, failed_login_attempts, locked_until, - can_be_assigned, initial - ) - SELECT - id, name, username, password_hash, role, created_at, updated_at, - is_active, last_login, failed_login_attempts, locked_until, - can_be_assigned, initial - FROM users_backup - `); - console.log('Copied data back from backup'); - - // Drop the backup table - db.exec('DROP TABLE users_backup'); - console.log('Dropped backup table'); - - // Re-enable foreign key constraints - db.pragma('foreign_keys = ON'); - console.log('Re-enabled foreign key constraints'); - - // Verify the migration - const userCount = db.prepare('SELECT COUNT(*) as count FROM users').get(); - console.log(`โœ… Migration completed successfully! Users table now has ${userCount.count} records`); - - // Verify the constraint allows the new role - console.log('โœ… CHECK constraint now includes: admin, team_lead, project_manager, user, read_only'); - -} catch (error) { - console.error('โŒ Migration failed:', error.message); - console.error('You may need to restore from backup manually'); - process.exit(1); -} \ No newline at end of file diff --git a/migrate-add-wartosc-zlecenia.mjs b/migrate-add-wartosc-zlecenia.mjs deleted file mode 100644 index 4478a6b..0000000 --- a/migrate-add-wartosc-zlecenia.mjs +++ /dev/null @@ -1,36 +0,0 @@ -import db from './src/lib/db.js'; - -console.log('Starting migration to add wartosc_zlecenia field to projects table...'); - -try { - // Check if wartosc_zlecenia column already exists - const schema = db.prepare("PRAGMA table_info(projects)").all(); - const hasWartoscZleceniaColumn = schema.some(column => column.name === 'wartosc_zlecenia'); - - if (hasWartoscZleceniaColumn) { - console.log("โœ… wartosc_zlecenia column already exists in projects table"); - } else { - // Add the wartosc_zlecenia column - db.prepare("ALTER TABLE projects ADD COLUMN wartosc_zlecenia REAL").run(); - console.log("โœ… Added 'wartosc_zlecenia' column to projects table"); - } - - // Verify the column was added - const updatedSchema = db.prepare("PRAGMA table_info(projects)").all(); - const wartoscZleceniaColumn = updatedSchema.find(column => column.name === 'wartosc_zlecenia'); - - if (wartoscZleceniaColumn) { - console.log("โœ… Migration completed successfully"); - console.log(`Column details: ${JSON.stringify(wartoscZleceniaColumn, null, 2)}`); - } else { - console.error("โŒ Migration failed - wartosc_zlecenia column not found"); - process.exit(1); - } - - db.close(); - console.log("Database connection closed"); - -} catch (error) { - console.error("โŒ Migration failed:", error.message); - process.exit(1); -} \ No newline at end of file diff --git a/migrate-contacts.mjs b/migrate-contacts.mjs deleted file mode 100644 index ba3447f..0000000 --- a/migrate-contacts.mjs +++ /dev/null @@ -1,46 +0,0 @@ -import db from './src/lib/db.js'; -import initializeDatabase from './src/lib/init-db.js'; - -console.log('๐Ÿš€ Initializing contacts tables...\n'); - -try { - // Run database initialization which will create the new contacts tables - initializeDatabase(); - - console.log('โœ… Contacts tables created successfully!\n'); - - // Check if there are projects with contact data in the old text field - const projectsWithContacts = db.prepare(` - SELECT project_id, project_name, contact - FROM projects - WHERE contact IS NOT NULL AND contact != '' - `).all(); - - if (projectsWithContacts.length > 0) { - console.log(`๐Ÿ“‹ Found ${projectsWithContacts.length} projects with contact information in the old text field.\n`); - console.log('Sample contacts that could be migrated:'); - projectsWithContacts.slice(0, 5).forEach(p => { - console.log(` - ${p.project_name}: "${p.contact}"`); - }); - console.log('\nโ„น๏ธ You can manually create contacts from the /contacts page and link them to projects.'); - console.log(' The old contact field will remain in the database for reference.\n'); - } else { - console.log('โ„น๏ธ No existing contact data found in projects.\n'); - } - - // Show table statistics - const contactsCount = db.prepare('SELECT COUNT(*) as count FROM contacts').get(); - const projectContactsCount = db.prepare('SELECT COUNT(*) as count FROM project_contacts').get(); - - console.log('๐Ÿ“Š Database Statistics:'); - console.log(` - Contacts: ${contactsCount.count}`); - console.log(` - Project-Contact Links: ${projectContactsCount.count}`); - console.log('\nโœจ Migration complete! You can now:'); - console.log(' 1. Visit /contacts to manage your contacts'); - console.log(' 2. Add/edit projects to link contacts'); - console.log(' 3. View linked contacts in project details\n'); - -} catch (error) { - console.error('โŒ Error during migration:', error); - process.exit(1); -} diff --git a/migrate-project-contacts.mjs b/migrate-project-contacts.mjs deleted file mode 100644 index adcc0db..0000000 --- a/migrate-project-contacts.mjs +++ /dev/null @@ -1,188 +0,0 @@ -import db from './src/lib/db.js'; -import initializeDatabase from './src/lib/init-db.js'; - -console.log('๐Ÿš€ Migrating contact data from projects...\n'); - -try { - // Run database initialization to ensure tables exist - initializeDatabase(); - - console.log('โœ… Database tables verified\n'); - - // Get all projects with contact data - const projectsWithContacts = db.prepare(` - SELECT project_id, project_name, contact - FROM projects - WHERE contact IS NOT NULL AND contact != '' AND TRIM(contact) != '' - `).all(); - - if (projectsWithContacts.length === 0) { - console.log('โ„น๏ธ No contact data found in projects to migrate.\n'); - process.exit(0); - } - - console.log(`๐Ÿ“‹ Found ${projectsWithContacts.length} projects with contact information\n`); - - let created = 0; - let linked = 0; - let skipped = 0; - - const createContact = db.prepare(` - INSERT INTO contacts (name, phone, email, contact_type, notes, is_active) - VALUES (?, ?, ?, 'project', ?, 1) - `); - - const linkContact = db.prepare(` - INSERT OR IGNORE INTO project_contacts (project_id, contact_id, is_primary, relationship_type) - VALUES (?, ?, 1, 'general') - `); - - // Process each project - for (const project of projectsWithContacts) { - try { - const contactText = project.contact.trim(); - - // Parse contact information - common formats: - // "Jan Kowalski, tel. 123-456-789" - // "Jan Kowalski 123-456-789" - // "123-456-789" - // "Jan Kowalski" - - let name = ''; - let phone = ''; - let email = ''; - let notes = ''; - - // Try to extract email - const emailPattern = /([a-zA-Z0-9._-]+@[a-zA-Z0-9._-]+\.[a-zA-Z0-9_-]+)/; - const emailMatch = contactText.match(emailPattern); - if (emailMatch) { - email = emailMatch[1].trim(); - } - - // Try to extract phone number (various formats) - const phonePatterns = [ - /(?:\+?48)?[\s-]?(\d{3}[\s-]?\d{3}[\s-]?\d{3})/, // Polish: 123-456-789, 123 456 789, +48 123456789 - /(?:\+?48)?[\s-]?(\d{9})/, // 9 digits - /tel\.?\s*[:.]?\s*([+\d\s-]+)/i, // tel. 123-456-789 - /phone\s*[:.]?\s*([+\d\s-]+)/i, // phone: 123-456-789 - /(\d{3}[-\s]?\d{3}[-\s]?\d{3})/, // Generic phone pattern - ]; - - for (const pattern of phonePatterns) { - const match = contactText.match(pattern); - if (match) { - phone = match[1] || match[0]; - phone = phone.replace(/\s+/g, ' ').trim(); - break; - } - } - - // Extract name (text before phone/email or comma) - let textForName = contactText; - - if (phone) { - // Remove phone from text to get name - textForName = textForName.replace(phone, ''); - } - if (email) { - // Remove email from text to get name - textForName = textForName.replace(email, ''); - } - - // Remove common prefixes like "tel.", "phone:", "email:", commas, etc. - name = textForName.replace(/tel\.?|phone:?|email:?|e-mail:?|,/gi, '').trim(); - - // Clean up name - name = name.replace(/^[,\s-]+|[,\s-]+$/g, '').trim(); - - // If we couldn't extract structured data, use project name and put original text in notes - if (!phone && !email) { - // No structured contact info found, put everything in notes - notes = `${contactText}`; - name = project.project_name; - } else if (!name) { - // We have phone/email but no clear name - name = project.project_name; - } - - // Check if this contact already exists (by name, phone, or email) - let existingContact = null; - if (phone) { - existingContact = db.prepare(` - SELECT contact_id FROM contacts - WHERE phone LIKE ? OR phone LIKE ? - `).get(`%${phone}%`, `%${phone.replace(/\s/g, '')}%`); - } - - if (!existingContact && email) { - existingContact = db.prepare(` - SELECT contact_id FROM contacts - WHERE LOWER(email) = LOWER(?) - `).get(email); - } - - if (!existingContact && name && name !== project.project_name) { - existingContact = db.prepare(` - SELECT contact_id FROM contacts - WHERE LOWER(name) = LOWER(?) - `).get(name); - } - - let contactId; - - if (existingContact) { - contactId = existingContact.contact_id; - console.log(` โ™ป๏ธ Using existing contact "${name}" for project "${project.project_name}"`); - } else { - // Create new contact - const result = createContact.run( - name, - phone || null, - email || null, - notes || `Przeniesiono z projektu: ${project.project_name}` - ); - contactId = result.lastInsertRowid; - created++; - - const contactInfo = []; - if (phone) contactInfo.push(`๐Ÿ“ž ${phone}`); - if (email) contactInfo.push(`๐Ÿ“ง ${email}`); - const infoStr = contactInfo.length > 0 ? ` (${contactInfo.join(', ')})` : ''; - - console.log(` โœจ Created contact "${name}"${infoStr} for project "${project.project_name}"`); - } - - // Link contact to project - linkContact.run(project.project_id, contactId); - linked++; - - } catch (error) { - console.error(` โŒ Error processing project "${project.project_name}":`, error.message); - skipped++; - } - } - - console.log('\n๐Ÿ“Š Migration Summary:'); - console.log(` - Contacts created: ${created}`); - console.log(` - Project-contact links created: ${linked}`); - console.log(` - Projects skipped: ${skipped}`); - console.log(` - Total projects processed: ${projectsWithContacts.length}`); - - // Show final statistics - const contactsCount = db.prepare('SELECT COUNT(*) as count FROM contacts').get(); - const projectContactsCount = db.prepare('SELECT COUNT(*) as count FROM project_contacts').get(); - - console.log('\n๐Ÿ“ˆ Current Database Statistics:'); - console.log(` - Total contacts: ${contactsCount.count}`); - console.log(` - Total project-contact links: ${projectContactsCount.count}`); - - console.log('\nโœจ Migration complete!'); - console.log(' - Visit /contacts to view and manage your contacts'); - console.log(' - Edit projects to see linked contacts'); - console.log(' - The old contact text field is preserved for reference\n'); - -} catch (error) { - console.error('โŒ Error during migration:', error); - process.exit(1); -} diff --git a/migrate-project-status.mjs b/migrate-project-status.mjs deleted file mode 100644 index 35d4359..0000000 --- a/migrate-project-status.mjs +++ /dev/null @@ -1,87 +0,0 @@ -import db from './src/lib/db.js'; - -console.log('Starting migration to add cancelled status to project_status constraint...'); - -try { - // Disable foreign key constraints temporarily - db.pragma('foreign_keys = OFF'); - console.log('Disabled foreign key constraints'); - - // Since SQLite doesn't support modifying CHECK constraints directly, - // we need to recreate the table with the new constraint - - // First, create a backup table with current data - db.exec('CREATE TABLE projects_backup AS SELECT * FROM projects'); - console.log('Created backup table'); - - // Drop the original table - db.exec('DROP TABLE projects'); - console.log('Dropped original table'); - - // Recreate the table with the updated constraint - db.exec(` - CREATE TABLE projects ( - project_id INTEGER PRIMARY KEY AUTOINCREMENT, - contract_id INTEGER, - project_name TEXT NOT NULL, - project_number TEXT NOT NULL, - address TEXT, - plot TEXT, - district TEXT, - unit TEXT, - city TEXT, - investment_number TEXT, - finish_date TEXT, - wp TEXT, - contact TEXT, - notes TEXT, - project_type TEXT CHECK(project_type IN ('design', 'construction', 'design+construction')) DEFAULT 'design', - project_status TEXT CHECK(project_status IN ('registered', 'in_progress_design', 'in_progress_construction', 'fulfilled', 'cancelled')) DEFAULT 'registered', - coordinates TEXT, - created_by TEXT, - assigned_to TEXT, - created_at TEXT, - updated_at TEXT, - FOREIGN KEY (contract_id) REFERENCES contracts(contract_id) - ) - `); - console.log('Created new table with updated constraint'); - - // Copy data back - db.exec('INSERT INTO projects SELECT * FROM projects_backup'); - console.log('Restored data from backup'); - - // Drop backup table - db.exec('DROP TABLE projects_backup'); - console.log('Cleaned up backup table'); - - // Re-enable foreign key constraints - db.pragma('foreign_keys = ON'); - console.log('Re-enabled foreign key constraints'); - - // Verify the new constraint - const schema = db.prepare('SELECT sql FROM sqlite_master WHERE type=\'table\' AND name=\'projects\'').get(); - console.log('New table definition:'); - console.log(schema.sql); - - console.log('Migration completed successfully!'); - -} catch (error) { - console.error('Migration failed:', error); - - // Re-enable foreign keys in case of error - try { - db.pragma('foreign_keys = ON'); - } catch (e) { - console.error('Failed to re-enable foreign keys:', e); - } - - // Try to restore from backup if it exists - try { - db.exec('DROP TABLE IF EXISTS projects'); - db.exec('ALTER TABLE projects_backup RENAME TO projects'); - console.log('Restored from backup due to error'); - } catch (restoreError) { - console.error('Failed to restore from backup:', restoreError); - } -} diff --git a/migrate-to-username.js b/migrate-to-username.js deleted file mode 100644 index 67e8ad8..0000000 --- a/migrate-to-username.js +++ /dev/null @@ -1,60 +0,0 @@ -import Database from "better-sqlite3"; - -const db = new Database("./data/database.sqlite"); - -console.log("๐Ÿ”„ Migrating database to username-based authentication...\n"); - -try { - // Check current table structure - const tableInfo = db.prepare("PRAGMA table_info(users)").all(); - console.log("Current users table columns:"); - tableInfo.forEach(col => console.log(` - ${col.name}: ${col.type}`)); - - const hasUsername = tableInfo.some(col => col.name === 'username'); - const hasEmail = tableInfo.some(col => col.name === 'email'); - - if (hasUsername) { - console.log("โœ… Username column already exists!"); - } else if (hasEmail) { - console.log("\n๐Ÿ“ Adding username column..."); - - // Add username column - db.exec(`ALTER TABLE users ADD COLUMN username TEXT;`); - console.log("โœ… Username column added"); - - // Copy email data to username for existing users - console.log("๐Ÿ“‹ Migrating existing email data to username..."); - const result = db.exec(`UPDATE users SET username = email WHERE username IS NULL;`); - console.log("โœ… Data migrated"); - - // Create unique index on username - console.log("๐Ÿ” Creating unique index on username..."); - try { - db.exec(`CREATE UNIQUE INDEX idx_users_username_unique ON users(username);`); - console.log("โœ… Unique index created"); - } catch (e) { - console.log("โ„น๏ธ Index already exists or couldn't be created:", e.message); - } - - // Verify migration - console.log("\n๐Ÿ” Verifying migration..."); - const users = db.prepare("SELECT id, name, username, email FROM users LIMIT 3").all(); - console.log("Sample users after migration:"); - users.forEach(user => { - console.log(` - ${user.name}: username="${user.username}", email="${user.email || 'NULL'}"`); - }); - - console.log("\nโœ… Migration completed successfully!"); - console.log("โ„น๏ธ You can now log in using usernames instead of emails"); - - } else { - console.log("โŒ Neither username nor email column found. Database may be corrupted."); - process.exit(1); - } - -} catch (error) { - console.error("โŒ Migration failed:", error.message); - process.exit(1); -} finally { - db.close(); -} diff --git a/run-migrations.sh b/run-migrations.sh deleted file mode 100644 index e186b6e..0000000 --- a/run-migrations.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/bash - -# Database migration runner for deployment -# This script runs all pending migrations in order - -echo "๐Ÿ”„ Running database migrations..." - -# List of migration scripts to run (in order) -MIGRATIONS=( - "migrate-add-team-lead-role.mjs" - "migrate-add-wartosc-zlecenia.mjs" -) - -for migration in "${MIGRATIONS[@]}"; do - if [ -f "$migration" ]; then - echo "Running migration: $migration" - if node "$migration"; then - echo "โœ… Migration $migration completed successfully" - # Optionally move completed migration to a completed folder - # mkdir -p migrations/completed - # mv "$migration" "migrations/completed/" - else - echo "โŒ Migration $migration failed" - exit 1 - fi - else - echo "Migration file $migration not found, skipping..." - fi -done - -echo "โœ… All migrations completed" \ No newline at end of file diff --git a/start-dev.bat b/start-dev.bat deleted file mode 100644 index cfe05a4..0000000 --- a/start-dev.bat +++ /dev/null @@ -1,6 +0,0 @@ -@echo off -cd /d "x:\projekty\panel" -echo Clearing Next.js cache... -if exist .next rmdir /s /q .next -echo Starting development server... -npm run dev diff --git a/test-audit-fix-direct.mjs b/test-audit-fix-direct.mjs deleted file mode 100644 index 24bc802..0000000 --- a/test-audit-fix-direct.mjs +++ /dev/null @@ -1,97 +0,0 @@ -// Test script to verify audit logging after our fixes -// This test shows what happens when API calls are made with proper authentication - -console.log("=== TESTING AUDIT LOGGING FIX ===\n"); - -// Simulate the flow that would happen in a real authenticated API call -async function testAuditLogging() { - try { - // Import the logging function - const { logAuditEventSafe, AUDIT_ACTIONS, RESOURCE_TYPES } = await import( - "./src/lib/auditLogSafe.js" - ); - - console.log("1. Testing audit logging with proper user session..."); - - // Simulate an authenticated session (like what req.auth would contain) - const mockAuthenticatedSession = { - user: { - id: "e42a4b036074ff7233942a0728557141", // Real user ID from our logs - email: "admin@localhost.com", - name: "Administrator", - role: "admin", - }, - expires: "2025-08-08T21:18:07.949Z", - }; - - // Simulate a null/undefined session (like unauthenticated requests) - const mockUnauthenticatedSession = null; - - // Test 1: Authenticated user logging - console.log("\n2. Testing with authenticated session:"); - await logAuditEventSafe({ - action: AUDIT_ACTIONS.PROJECT_VIEW, - userId: mockAuthenticatedSession?.user?.id || null, - resourceType: RESOURCE_TYPES.PROJECT, - resourceId: "test-project-123", - ipAddress: "127.0.0.1", - userAgent: "Test Browser", - details: { - test: "authenticated_user_test", - timestamp: new Date().toISOString(), - }, - }); - - // Test 2: Unauthenticated user logging (should result in null userId) - console.log("\n3. Testing with unauthenticated session:"); - await logAuditEventSafe({ - action: AUDIT_ACTIONS.LOGIN_FAILED, - userId: mockUnauthenticatedSession?.user?.id || null, - resourceType: RESOURCE_TYPES.SESSION, - resourceId: null, - ipAddress: "127.0.0.1", - userAgent: "Test Browser", - details: { - test: "unauthenticated_user_test", - email: "hacker@test.com", - reason: "invalid_credentials", - }, - }); - - // Test 3: Check what we just logged - console.log("\n4. Checking the audit events we just created..."); - const { getAuditLogs } = await import("./src/lib/auditLog.js"); - const latestLogs = await getAuditLogs({ limit: 2 }); - - console.log("Latest 2 audit events:"); - latestLogs.forEach((log, index) => { - const userDisplay = log.user_id ? `user ${log.user_id}` : "NULL USER ID"; - console.log( - `${index + 1}. ${log.timestamp} - ${log.action} by ${userDisplay} on ${ - log.resource_type - }:${log.resource_id || "N/A"}` - ); - if (log.details) { - const details = - typeof log.details === "string" - ? JSON.parse(log.details) - : log.details; - console.log(` Details: ${JSON.stringify(details, null, 4)}`); - } - }); - - console.log("\n5. CONCLUSION:"); - console.log("โœ… The audit logging system is working correctly!"); - console.log("โœ… Authenticated users get proper user IDs logged"); - console.log( - "โœ… Unauthenticated requests get NULL user IDs (which is expected)" - ); - console.log( - "โœ… The logApiActionSafe function will extract userId from session?.user?.id correctly" - ); - } catch (error) { - console.error("Test failed:", error); - } -} - -testAuditLogging(); diff --git a/test-audit-logging.mjs b/test-audit-logging.mjs deleted file mode 100644 index 19fc5fb..0000000 --- a/test-audit-logging.mjs +++ /dev/null @@ -1,138 +0,0 @@ -import { - logAuditEvent, - getAuditLogs, - getAuditLogStats, - AUDIT_ACTIONS, - RESOURCE_TYPES, -} from "./src/lib/auditLog.js"; - -// Test audit logging functionality -console.log("Testing Audit Logging System...\n"); - -// Test 1: Log some sample events -console.log("1. Creating sample audit events..."); - -logAuditEvent({ - action: AUDIT_ACTIONS.LOGIN, - userId: "user123", - resourceType: RESOURCE_TYPES.SESSION, - ipAddress: "192.168.1.100", - userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36", - details: { - email: "test@example.com", - role: "user", - }, -}); - -logAuditEvent({ - action: AUDIT_ACTIONS.PROJECT_CREATE, - userId: "user123", - resourceType: RESOURCE_TYPES.PROJECT, - resourceId: "proj-456", - ipAddress: "192.168.1.100", - userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36", - details: { - project_name: "Test Project", - project_number: "TP-001", - }, -}); - -logAuditEvent({ - action: AUDIT_ACTIONS.PROJECT_UPDATE, - userId: "user456", - resourceType: RESOURCE_TYPES.PROJECT, - resourceId: "proj-456", - ipAddress: "192.168.1.101", - userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36", - details: { - updatedFields: ["project_name", "address"], - oldValues: { project_name: "Test Project" }, - newValues: { project_name: "Updated Test Project" }, - }, -}); - -logAuditEvent({ - action: AUDIT_ACTIONS.LOGIN_FAILED, - userId: null, - resourceType: RESOURCE_TYPES.SESSION, - ipAddress: "192.168.1.102", - userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36", - details: { - email: "hacker@evil.com", - reason: "invalid_password", - failed_attempts: 3, - }, -}); - -console.log("Sample events created!\n"); - -// Test 2: Retrieve audit logs -console.log("2. Retrieving audit logs..."); - -const allLogs = getAuditLogs(); -console.log(`Found ${allLogs.length} total audit events`); - -// Show the latest 3 events -console.log("\nLatest audit events:"); -allLogs.slice(0, 3).forEach((log, index) => { - console.log( - `${index + 1}. ${log.timestamp} - ${log.action} by user ${ - log.user_id || "anonymous" - } on ${log.resource_type}:${log.resource_id || "N/A"}` - ); - if (log.details) { - console.log(` Details: ${JSON.stringify(log.details, null, 2)}`); - } -}); - -// Test 3: Filtered queries -console.log("\n3. Testing filtered queries..."); - -const loginEvents = getAuditLogs({ action: AUDIT_ACTIONS.LOGIN }); -console.log(`Found ${loginEvents.length} login events`); - -const projectEvents = getAuditLogs({ resourceType: RESOURCE_TYPES.PROJECT }); -console.log(`Found ${projectEvents.length} project-related events`); - -const user123Events = getAuditLogs({ userId: "user123" }); -console.log(`Found ${user123Events.length} events by user123`); - -// Test 4: Statistics -console.log("\n4. Getting audit statistics..."); - -const stats = getAuditLogStats(); -console.log("Overall statistics:"); -console.log(`- Total events: ${stats.total}`); -console.log("- Action breakdown:"); -stats.actionBreakdown.forEach((action) => { - console.log(` - ${action.action}: ${action.count}`); -}); -console.log("- User breakdown:"); -stats.userBreakdown.forEach((user) => { - console.log( - ` - ${user.user_name || user.user_id || "Anonymous"}: ${user.count}` - ); -}); -console.log("- Resource breakdown:"); -stats.resourceBreakdown.forEach((resource) => { - console.log(` - ${resource.resource_type}: ${resource.count}`); -}); - -// Test 5: Date range filtering -console.log("\n5. Testing date range filtering..."); - -const now = new Date(); -const oneHourAgo = new Date(now.getTime() - 60 * 60 * 1000); - -const recentLogs = getAuditLogs({ - startDate: oneHourAgo.toISOString(), - endDate: now.toISOString(), -}); -console.log(`Found ${recentLogs.length} events in the last hour`); - -console.log("\nAudit logging test completed successfully! โœ…"); -console.log("\nTo view audit logs in the application:"); -console.log("1. Start your Next.js application"); -console.log("2. Login as an admin or project manager"); -console.log("3. Navigate to /admin/audit-logs"); -console.log("4. Use the filters to explore the audit trail"); diff --git a/test-auth-api.mjs b/test-auth-api.mjs deleted file mode 100644 index a88b3f4..0000000 --- a/test-auth-api.mjs +++ /dev/null @@ -1,109 +0,0 @@ -// Test authenticated API access using NextAuth.js client-side approach - -const BASE_URL = 'http://localhost:3000'; - -async function testAuthenticatedAPI() { - console.log('๐Ÿ” Testing Authenticated API Access\n'); - - try { - // Test 1: Check if server is running - console.log('1๏ธโƒฃ Checking server status...'); - const healthResponse = await fetch(`${BASE_URL}/api/auth/session`); - console.log(`Server status: ${healthResponse.status}`); - - if (!healthResponse.ok) { - console.log('โŒ Server not responding properly'); - return; - } - - // Test 2: Test unauthenticated access to protected endpoints - console.log('\n2๏ธโƒฃ Testing unauthenticated access...'); - const protectedEndpoints = [ - '/api/projects', - '/api/contracts', - '/api/tasks', - '/api/project-tasks' - ]; - - for (const endpoint of protectedEndpoints) { - const response = await fetch(`${BASE_URL}${endpoint}`); - console.log(`${endpoint}: ${response.status} ${response.status === 401 ? 'โœ… (properly protected)' : 'โŒ (not protected)'}`); - } - - // Test 3: Check protected pages - console.log('\n3๏ธโƒฃ Testing protected pages...'); - const protectedPages = ['/projects', '/contracts', '/tasks']; - - for (const page of protectedPages) { - const response = await fetch(`${BASE_URL}${page}`, { - redirect: 'manual' - }); - - if (response.status === 302) { - const location = response.headers.get('location'); - if (location && location.includes('/auth/signin')) { - console.log(`${page}: โœ… Properly redirects to sign-in`); - } else { - console.log(`${page}: โš ๏ธ Redirects to: ${location}`); - } - } else if (response.status === 200) { - console.log(`${page}: โŒ Accessible without authentication`); - } else { - console.log(`${page}: โ“ Status ${response.status}`); - } - } - - // Test 4: Test sign-in page accessibility - console.log('\n4๏ธโƒฃ Testing sign-in page...'); - const signinResponse = await fetch(`${BASE_URL}/auth/signin`); - if (signinResponse.ok) { - console.log('โœ… Sign-in page accessible'); - const content = await signinResponse.text(); - const hasEmailField = content.includes('name="email"') || content.includes('id="email"'); - const hasPasswordField = content.includes('name="password"') || content.includes('id="password"'); - console.log(` Email field: ${hasEmailField ? 'โœ…' : 'โŒ'}`); - console.log(` Password field: ${hasPasswordField ? 'โœ…' : 'โŒ'}`); - } else { - console.log('โŒ Sign-in page not accessible'); - } - - // Test 5: Check NextAuth.js providers endpoint - console.log('\n5๏ธโƒฃ Testing NextAuth.js configuration...'); - const providersResponse = await fetch(`${BASE_URL}/api/auth/providers`); - if (providersResponse.ok) { - const providers = await providersResponse.json(); - console.log('โœ… NextAuth.js providers endpoint accessible'); - console.log('Available providers:', Object.keys(providers)); - } else { - console.log('โŒ NextAuth.js providers endpoint failed'); - } - - // Test 6: Check CSRF token endpoint - console.log('\n6๏ธโƒฃ Testing CSRF token...'); - const csrfResponse = await fetch(`${BASE_URL}/api/auth/csrf`); - if (csrfResponse.ok) { - const csrf = await csrfResponse.json(); - console.log('โœ… CSRF token endpoint accessible'); - console.log('CSRF token available:', !!csrf.csrfToken); - } else { - console.log('โŒ CSRF token endpoint failed'); - } - - console.log('\n๐ŸŽฏ Manual Testing Instructions:'); - console.log('1. Open browser to: http://localhost:3000/auth/signin'); - console.log('2. Use credentials:'); - console.log(' Email: admin@localhost.com'); - console.log(' Password: admin123456'); - console.log('3. After login, test these pages:'); - protectedPages.forEach(page => { - console.log(` - http://localhost:3000${page}`); - }); - console.log('4. Test API endpoints with browser dev tools or Postman'); - - } catch (error) { - console.error('โŒ Test failed with error:', error.message); - } -} - -// Run the test -testAuthenticatedAPI(); diff --git a/test-auth-detailed.mjs b/test-auth-detailed.mjs deleted file mode 100644 index bce59fa..0000000 --- a/test-auth-detailed.mjs +++ /dev/null @@ -1,40 +0,0 @@ -// Test script to verify API route protection with better error handling -const BASE_URL = 'http://localhost:3000'; - -// Test unauthenticated access to protected routes -async function testProtectedRoutes() { - console.log('๐Ÿ” Testing Authorization Setup\n'); - - const protectedRoutes = [ - '/api/projects', - '/api/contracts' - ]; - - console.log('Testing unauthenticated access to protected routes...\n'); - - for (const route of protectedRoutes) { - try { - const response = await fetch(`${BASE_URL}${route}`); - const contentType = response.headers.get('content-type'); - - console.log(`Route: ${route}`); - console.log(`Status: ${response.status}`); - console.log(`Content-Type: ${contentType}`); - - if (contentType && contentType.includes('application/json')) { - const data = await response.json(); - console.log(`Response: ${JSON.stringify(data)}`); - } else { - const text = await response.text(); - console.log(`Response (first 200 chars): ${text.substring(0, 200)}...`); - } - - console.log('---\n'); - } catch (error) { - console.log(`โŒ ${route} - ERROR: ${error.message}\n`); - } - } -} - -// Run the test -testProtectedRoutes().catch(console.error); diff --git a/test-auth-pages.mjs b/test-auth-pages.mjs deleted file mode 100644 index 8320616..0000000 --- a/test-auth-pages.mjs +++ /dev/null @@ -1,127 +0,0 @@ -// Test authenticated access to pages and API endpoints -const BASE_URL = 'http://localhost:3000'; - -// Helper to extract cookies from response headers -function extractCookies(response) { - const cookies = []; - const setCookieHeaders = response.headers.get('set-cookie'); - if (setCookieHeaders) { - cookies.push(setCookieHeaders); - } - return cookies.join('; '); -} - -// Test authenticated access -async function testAuthenticatedAccess() { - console.log('๐Ÿ” Testing Authenticated Access\n'); - - // Step 1: Get the sign-in page to check if it loads - console.log('1๏ธโƒฃ Testing sign-in page access...'); - try { - const signInResponse = await fetch(`${BASE_URL}/auth/signin`); - console.log(`โœ… Sign-in page: ${signInResponse.status} ${signInResponse.statusText}`); - - if (signInResponse.status === 200) { - const pageContent = await signInResponse.text(); - const hasForm = pageContent.includes('Sign in to your account'); - console.log(` Form present: ${hasForm ? 'โœ… Yes' : 'โŒ No'}`); - } - } catch (error) { - console.log(`โŒ Sign-in page error: ${error.message}`); - } - - console.log('\n2๏ธโƒฃ Testing authentication endpoint...'); - - // Step 2: Test the authentication API endpoint - try { - const sessionResponse = await fetch(`${BASE_URL}/api/auth/session`); - console.log(`โœ… Session endpoint: ${sessionResponse.status} ${sessionResponse.statusText}`); - - if (sessionResponse.status === 200) { - const sessionData = await sessionResponse.json(); - console.log(` Session data: ${JSON.stringify(sessionData)}`); - } - } catch (error) { - console.log(`โŒ Session endpoint error: ${error.message}`); - } - - console.log('\n3๏ธโƒฃ Testing CSRF token endpoint...'); - - // Step 3: Get CSRF token - try { - const csrfResponse = await fetch(`${BASE_URL}/api/auth/csrf`); - console.log(`โœ… CSRF endpoint: ${csrfResponse.status} ${csrfResponse.statusText}`); - - if (csrfResponse.status === 200) { - const csrfData = await csrfResponse.json(); - console.log(` CSRF token: ${csrfData.csrfToken ? 'โœ… Present' : 'โŒ Missing'}`); - } - } catch (error) { - console.log(`โŒ CSRF endpoint error: ${error.message}`); - } - - console.log('\n4๏ธโƒฃ Testing main dashboard page (unauthenticated)...'); - - // Step 4: Test main page redirect - try { - const mainPageResponse = await fetch(`${BASE_URL}/`, { - redirect: 'manual' // Don't follow redirects automatically - }); - console.log(`โœ… Main page: ${mainPageResponse.status} ${mainPageResponse.statusText}`); - - if (mainPageResponse.status === 307 || mainPageResponse.status === 302) { - const location = mainPageResponse.headers.get('location'); - console.log(` Redirects to: ${location}`); - console.log(` Correct redirect: ${location && location.includes('/auth/signin') ? 'โœ… Yes' : 'โŒ No'}`); - } - } catch (error) { - console.log(`โŒ Main page error: ${error.message}`); - } - - console.log('\n5๏ธโƒฃ Testing projects page (unauthenticated)...'); - - // Step 5: Test projects page redirect - try { - const projectsPageResponse = await fetch(`${BASE_URL}/projects`, { - redirect: 'manual' - }); - console.log(`โœ… Projects page: ${projectsPageResponse.status} ${projectsPageResponse.statusText}`); - - if (projectsPageResponse.status === 307 || projectsPageResponse.status === 302) { - const location = projectsPageResponse.headers.get('location'); - console.log(` Redirects to: ${location}`); - console.log(` Correct redirect: ${location && location.includes('/auth/signin') ? 'โœ… Yes' : 'โŒ No'}`); - } - } catch (error) { - console.log(`โŒ Projects page error: ${error.message}`); - } - - console.log('\n6๏ธโƒฃ Testing API endpoints (unauthenticated)...'); - - // Step 6: Test API endpoints - const apiEndpoints = ['/api/projects', '/api/contracts', '/api/tasks/templates']; - - for (const endpoint of apiEndpoints) { - try { - const response = await fetch(`${BASE_URL}${endpoint}`); - const data = await response.json(); - - if (response.status === 401) { - console.log(`โœ… ${endpoint}: Protected (401) - ${data.error}`); - } else { - console.log(`โŒ ${endpoint}: Not protected (${response.status})`); - } - } catch (error) { - console.log(`โŒ ${endpoint}: Error - ${error.message}`); - } - } - - console.log('\n๐Ÿ“‹ Summary:'); - console.log('- Sign-in page should be accessible'); - console.log('- Protected pages should redirect to /auth/signin'); - console.log('- Protected API endpoints should return 401 with JSON error'); - console.log('- Auth endpoints (/api/auth/*) should be accessible'); -} - -// Run the test -testAuthenticatedAccess().catch(console.error); diff --git a/test-auth-session.mjs b/test-auth-session.mjs deleted file mode 100644 index 568f803..0000000 --- a/test-auth-session.mjs +++ /dev/null @@ -1,37 +0,0 @@ -import { auth } from "@/lib/auth"; - -// Test what the auth session looks like -console.log("Testing authentication session structure...\n"); - -async function testAuth() { - try { - // Create a mock request - const mockReq = { - url: "http://localhost:3000/api/projects", - method: "GET", - headers: new Map([ - ["cookie", ""], // Add any cookies if needed - ]), - }; - - // This is how the auth middleware would wrap a handler - const testHandler = auth(async (req) => { - console.log("=== Authentication Session Debug ==="); - console.log("req.auth:", JSON.stringify(req.auth, null, 2)); - console.log("req.auth?.user:", JSON.stringify(req.auth?.user, null, 2)); - console.log("req.auth?.user?.id:", req.auth?.user?.id); - console.log("req.user:", JSON.stringify(req.user, null, 2)); - console.log("req.user?.id:", req.user?.id); - - return { success: true }; - }); - - // This would normally be called by Next.js - const result = await testHandler(mockReq); - console.log("Handler result:", result); - } catch (error) { - console.error("Auth test failed:", error); - } -} - -testAuth(); diff --git a/test-auth.mjs b/test-auth.mjs deleted file mode 100644 index be08343..0000000 --- a/test-auth.mjs +++ /dev/null @@ -1,49 +0,0 @@ -// Test script to verify API route protection -const BASE_URL = 'http://localhost:3000'; - -// Test unauthenticated access to protected routes -async function testProtectedRoutes() { - console.log('๐Ÿ” Testing Authorization Setup\n'); - - const protectedRoutes = [ - '/api/projects', - '/api/contracts', - '/api/tasks/templates', - '/api/project-tasks', - '/api/notes', - '/api/all-project-tasks' - ]; - - console.log('Testing unauthenticated access to protected routes...\n'); - - for (const route of protectedRoutes) { - try { - const response = await fetch(`${BASE_URL}${route}`); - const data = await response.json(); - - if (response.status === 401) { - console.log(`โœ… ${route} - PROTECTED (401 Unauthorized)`); - } else { - console.log(`โŒ ${route} - NOT PROTECTED (${response.status})`); - console.log(` Response: ${JSON.stringify(data).substring(0, 100)}...`); - } - } catch (error) { - console.log(`โŒ ${route} - ERROR: ${error.message}`); - } - } - - console.log('\n๐Ÿ” Testing authentication endpoint...\n'); - - // Test NextAuth endpoint - try { - const response = await fetch(`${BASE_URL}/api/auth/session`); - const data = await response.json(); - console.log(`โœ… /api/auth/session - Available (${response.status})`); - console.log(` Response: ${JSON.stringify(data)}`); - } catch (error) { - console.log(`โŒ /api/auth/session - ERROR: ${error.message}`); - } -} - -// Run the test -testProtectedRoutes().catch(console.error); diff --git a/test-complete-auth.mjs b/test-complete-auth.mjs deleted file mode 100644 index 4d3d653..0000000 --- a/test-complete-auth.mjs +++ /dev/null @@ -1,115 +0,0 @@ -// Complete authentication flow test -const BASE_URL = 'http://localhost:3000'; - -async function testCompleteAuthFlow() { - console.log('๐Ÿ” Testing Complete Authentication Flow\n'); - - // Test 1: Verify unauthenticated access is properly blocked - console.log('1๏ธโƒฃ Testing unauthenticated access protection...'); - - const protectedRoutes = [ - { path: '/', name: 'Dashboard' }, - { path: '/projects', name: 'Projects Page' }, - { path: '/tasks/templates', name: 'Tasks Page' } - ]; - - for (const route of protectedRoutes) { - try { - const response = await fetch(`${BASE_URL}${route.path}`, { - redirect: 'manual' - }); - - if (response.status === 302 || response.status === 307) { - const location = response.headers.get('location'); - if (location && location.includes('/auth/signin')) { - console.log(` โœ… ${route.name}: Properly redirects to sign-in`); - } else { - console.log(` โŒ ${route.name}: Redirects to wrong location: ${location}`); - } - } else { - console.log(` โŒ ${route.name}: Not protected (${response.status})`); - } - } catch (error) { - console.log(` โŒ ${route.name}: Error - ${error.message}`); - } - } - - // Test 2: Verify API protection - console.log('\n2๏ธโƒฃ Testing API protection...'); - - const apiRoutes = ['/api/projects', '/api/contracts', '/api/tasks/templates']; - - for (const route of apiRoutes) { - try { - const response = await fetch(`${BASE_URL}${route}`); - const data = await response.json(); - - if (response.status === 401 && data.error === 'Authentication required') { - console.log(` โœ… ${route}: Properly protected`); - } else { - console.log(` โŒ ${route}: Not protected (${response.status}) - ${JSON.stringify(data)}`); - } - } catch (error) { - console.log(` โŒ ${route}: Error - ${error.message}`); - } - } - - // Test 3: Verify auth endpoints work - console.log('\n3๏ธโƒฃ Testing NextAuth endpoints...'); - - const authEndpoints = [ - { path: '/api/auth/session', name: 'Session' }, - { path: '/api/auth/providers', name: 'Providers' }, - { path: '/api/auth/csrf', name: 'CSRF' } - ]; - - for (const endpoint of authEndpoints) { - try { - const response = await fetch(`${BASE_URL}${endpoint.path}`); - - if (response.status === 200) { - console.log(` โœ… ${endpoint.name}: Working (200)`); - } else { - console.log(` โŒ ${endpoint.name}: Error (${response.status})`); - } - } catch (error) { - console.log(` โŒ ${endpoint.name}: Error - ${error.message}`); - } - } - - // Test 4: Verify sign-in page accessibility - console.log('\n4๏ธโƒฃ Testing sign-in page...'); - - try { - const response = await fetch(`${BASE_URL}/auth/signin`); - - if (response.status === 200) { - const html = await response.text(); - const hasForm = html.includes('Sign in to your account'); - const hasEmailField = html.includes('email'); - const hasPasswordField = html.includes('password'); - - console.log(` โœ… Sign-in page: Accessible (200)`); - console.log(` โœ… Form present: ${hasForm ? 'Yes' : 'No'}`); - console.log(` โœ… Email field: ${hasEmailField ? 'Yes' : 'No'}`); - console.log(` โœ… Password field: ${hasPasswordField ? 'Yes' : 'No'}`); - } else { - console.log(` โŒ Sign-in page: Error (${response.status})`); - } - } catch (error) { - console.log(` โŒ Sign-in page: Error - ${error.message}`); - } - - console.log('\n๐Ÿ“‹ Summary:'); - console.log('โœ… All protected pages redirect to sign-in'); - console.log('โœ… All API endpoints require authentication'); - console.log('โœ… NextAuth endpoints are functional'); - console.log('โœ… Sign-in page is accessible and complete'); - console.log('\n๐ŸŽ‰ Authentication system is fully functional!'); - console.log('\n๐Ÿ“ Next steps:'); - console.log(' โ€ข Visit http://localhost:3000/auth/signin'); - console.log(' โ€ข Login with: admin@localhost / admin123456'); - console.log(' โ€ข Access the protected application!'); -} - -testCompleteAuthFlow().catch(console.error); diff --git a/test-contacts-query.mjs b/test-contacts-query.mjs deleted file mode 100644 index 80ce5d1..0000000 --- a/test-contacts-query.mjs +++ /dev/null @@ -1,54 +0,0 @@ -import db from './src/lib/db.js'; - -console.log('Testing contacts query...\n'); - -try { - // Test 1: Basic query - console.log('Test 1: Basic contact query'); - const basic = db.prepare('SELECT contact_id, name FROM contacts WHERE is_active = 1 LIMIT 3').all(); - console.log('โœ“ Basic query works:', basic.length, 'contacts\n'); - - // Test 2: With LEFT JOIN - console.log('Test 2: With project_contacts join'); - const withJoin = db.prepare(` - SELECT c.contact_id, c.name, COUNT(pc.project_id) as count - FROM contacts c - LEFT JOIN project_contacts pc ON c.contact_id = pc.contact_id - WHERE c.is_active = 1 - GROUP BY c.contact_id - LIMIT 3 - `).all(); - console.log('โœ“ Join query works:', withJoin.length, 'contacts\n'); - - // Test 3: With both joins - console.log('Test 3: With both joins (no CASE)'); - const bothJoins = db.prepare(` - SELECT c.contact_id, c.name, COUNT(p.project_id) as count - FROM contacts c - LEFT JOIN project_contacts pc ON c.contact_id = pc.contact_id - LEFT JOIN projects p ON pc.project_id = p.project_id - WHERE c.is_active = 1 - GROUP BY c.contact_id - LIMIT 3 - `).all(); - console.log('โœ“ Both joins work:', bothJoins.length, 'contacts\n'); - - // Test 4: With CASE statement - console.log('Test 4: With CASE statement'); - const withCase = db.prepare(` - SELECT c.contact_id, c.name, - COUNT(DISTINCT CASE WHEN p.is_deleted = 0 THEN p.project_id ELSE NULL END) as count - FROM contacts c - LEFT JOIN project_contacts pc ON c.contact_id = pc.contact_id - LEFT JOIN projects p ON pc.project_id = p.project_id - WHERE c.is_active = 1 - GROUP BY c.contact_id - LIMIT 3 - `).all(); - console.log('โœ“ CASE query works:', withCase.length, 'contacts'); - withCase.forEach(c => console.log(` ${c.name}: ${c.count} active projects`)); - -} catch (error) { - console.error('โŒ Query failed:', error.message); - console.error(error.stack); -} diff --git a/test-create-function.mjs b/test-create-function.mjs deleted file mode 100644 index c214482..0000000 --- a/test-create-function.mjs +++ /dev/null @@ -1,40 +0,0 @@ -import { createProject } from "./src/lib/queries/projects.js"; -import initializeDatabase from "./src/lib/init-db.js"; - -// Initialize database -initializeDatabase(); - -console.log("Testing createProject function...\n"); - -const testProjectData = { - contract_id: 1, // Assuming contract 1 exists - project_name: "Test Project - User Tracking", - address: "Test Address 123", - plot: "123/456", - district: "Test District", - unit: "Test Unit", - city: "Test City", - investment_number: "TEST-2025-001", - finish_date: "2025-12-31", - wp: "TEST/2025/001", - contact: "test@example.com", - notes: "Test project with user tracking", - project_type: "design", - project_status: "registered", - coordinates: "50.0,20.0", - assigned_to: "e42a4b036074ff7233942a0728557141", // admin user ID -}; - -try { - console.log("Creating test project with admin user as creator..."); - const result = createProject( - testProjectData, - "e42a4b036074ff7233942a0728557141" - ); - console.log("โœ… Project created successfully!"); - console.log("Result:", result); - console.log("Project ID:", result.lastInsertRowid); -} catch (error) { - console.error("โŒ Error creating project:", error.message); - console.error("Stack:", error.stack); -} diff --git a/test-current-audit-logs.mjs b/test-current-audit-logs.mjs deleted file mode 100644 index 6adae6d..0000000 --- a/test-current-audit-logs.mjs +++ /dev/null @@ -1,124 +0,0 @@ -import { - logAuditEvent, - getAuditLogs, - getAuditLogStats, - AUDIT_ACTIONS, - RESOURCE_TYPES, -} from "./src/lib/auditLog.js"; - -// Test audit logging functionality -console.log("Testing Audit Logging System...\n"); - -async function testAuditLogging() { - try { - // Test 1: Check existing audit logs - console.log("1. Checking existing audit logs..."); - const existingLogs = await getAuditLogs({ limit: 10 }); - console.log(`Found ${existingLogs.length} existing audit events`); - - if (existingLogs.length > 0) { - console.log("\nLatest audit events:"); - existingLogs.slice(0, 5).forEach((log, index) => { - console.log( - `${index + 1}. ${log.timestamp} - ${log.action} by user ${ - log.user_id || "NULL" - } on ${log.resource_type}:${log.resource_id || "N/A"}` - ); - if (log.details) { - console.log( - ` Details: ${JSON.stringify(JSON.parse(log.details), null, 2)}` - ); - } - }); - } - - // Check for null userIds - const nullUserIdLogs = await getAuditLogs(); - const nullUserCount = nullUserIdLogs.filter( - (log) => log.user_id === null - ).length; - console.log( - `\nFound ${nullUserCount} audit events with NULL user_id out of ${nullUserIdLogs.length} total` - ); - - // Test 2: Log some sample events with different user scenarios - console.log("\n2. Creating sample audit events..."); - - await logAuditEvent({ - action: AUDIT_ACTIONS.LOGIN, - userId: "user123", - resourceType: RESOURCE_TYPES.SESSION, - ipAddress: "192.168.1.100", - userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36", - details: { - email: "test@example.com", - role: "user", - }, - }); - - await logAuditEvent({ - action: AUDIT_ACTIONS.PROJECT_CREATE, - userId: "user123", - resourceType: RESOURCE_TYPES.PROJECT, - resourceId: "proj-456", - ipAddress: "192.168.1.100", - userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36", - details: { - project_name: "Test Project", - project_number: "TP-001", - }, - }); - - // Test null userId scenario - await logAuditEvent({ - action: AUDIT_ACTIONS.LOGIN_FAILED, - userId: null, - resourceType: RESOURCE_TYPES.SESSION, - ipAddress: "192.168.1.102", - userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36", - details: { - email: "hacker@evil.com", - reason: "invalid_password", - failed_attempts: 3, - }, - }); - - console.log("Sample events created!\n"); - - // Test 3: Check new logs - console.log("3. Checking audit logs after test events..."); - const newLogs = await getAuditLogs({ limit: 5 }); - console.log(`Latest 5 audit events:`); - newLogs.forEach((log, index) => { - console.log( - `${index + 1}. ${log.timestamp} - ${log.action} by user ${ - log.user_id || "NULL" - } on ${log.resource_type}:${log.resource_id || "N/A"}` - ); - }); - - // Test 4: Statistics - console.log("\n4. Getting audit log statistics..."); - const stats = await getAuditLogStats(); - console.log(`Total events: ${stats.total}`); - - console.log("\nAction breakdown:"); - stats.actionBreakdown.forEach((item) => { - console.log(` ${item.action}: ${item.count}`); - }); - - console.log("\nUser breakdown:"); - stats.userBreakdown.slice(0, 5).forEach((item) => { - console.log( - ` ${item.user_id || "NULL"} (${item.user_name || "Unknown"}): ${ - item.count - }` - ); - }); - } catch (error) { - console.error("Test failed:", error); - } -} - -// Run the test -testAuditLogging(); diff --git a/test-date-formatting.js b/test-date-formatting.js deleted file mode 100644 index 0a7703d..0000000 --- a/test-date-formatting.js +++ /dev/null @@ -1,56 +0,0 @@ -// Test script to verify date formatting -import { formatDate, formatDateForInput } from "./src/lib/utils.js"; - -console.log("Testing Date Formatting Functions...\n"); - -// Test cases -const testDates = [ - "2024-01-15", - "2024-12-25T14:30:00", - "2024-06-01", - new Date("2024-03-10"), - new Date("2024-09-22T09:15:30"), - null, - undefined, - "invalid-date", -]; - -console.log("formatDate() tests (DD.MM.YYYY format):"); -testDates.forEach((date, index) => { - try { - const result = formatDate(date); - console.log(`${index + 1}. ${JSON.stringify(date)} -> "${result}"`); - } catch (error) { - console.log( - `${index + 1}. ${JSON.stringify(date)} -> ERROR: ${error.message}` - ); - } -}); - -console.log("\nformatDate() with time tests (DD.MM.YYYY HH:MM format):"); -testDates.forEach((date, index) => { - try { - const result = formatDate(date, { includeTime: true }); - console.log(`${index + 1}. ${JSON.stringify(date)} -> "${result}"`); - } catch (error) { - console.log( - `${index + 1}. ${JSON.stringify(date)} -> ERROR: ${error.message}` - ); - } -}); - -console.log( - "\nformatDateForInput() tests (YYYY-MM-DD format for HTML inputs):" -); -testDates.forEach((date, index) => { - try { - const result = formatDateForInput(date); - console.log(`${index + 1}. ${JSON.stringify(date)} -> "${result}"`); - } catch (error) { - console.log( - `${index + 1}. ${JSON.stringify(date)} -> ERROR: ${error.message}` - ); - } -}); - -console.log("\nDate formatting verification complete!"); diff --git a/test-dropdown-comprehensive.html b/test-dropdown-comprehensive.html deleted file mode 100644 index ca2a30d..0000000 --- a/test-dropdown-comprehensive.html +++ /dev/null @@ -1,417 +0,0 @@ - - - - - - Comprehensive Dropdown Test - - - - -
-

- Dropdown Component Validation -

- - -
-

- โœ… Test 1: Basic Dropdown Structure -

- - - -
- - -
-

- โœ… Test 2: Dropdown in Table Context -

-
- - - - - - - - - - - - - - - -
- Task - - Status - - Project Status -
Sample Task 1 -
- - -
-
-
- - -
-
-
-
- - -
-

- ๐Ÿงช Test Results -

-
-

โณ Click the dropdown buttons above to test functionality...

-
- -
-

Expected Behavior:

-
    -
  • โœ… Dropdowns should appear immediately when clicked
  • -
  • โœ… Red border and yellow debug header should be visible
  • -
  • - โœ… Dropdown should appear above all other elements (z-index test) -
  • -
  • โœ… Clicking outside should close the dropdown
  • -
  • โœ… Dropdown should not be clipped by table overflow
  • -
-
-
-
- - - - diff --git a/test-dropdown.html b/test-dropdown.html deleted file mode 100644 index 9246a0a..0000000 --- a/test-dropdown.html +++ /dev/null @@ -1,156 +0,0 @@ - - - - - - Dropdown Test - - - - -

Dropdown Visibility Test

- - -
-

Basic Dropdown Test

-
- - -
-
- - -
-

High Z-Index Test

-
- - -
-
- - -
-

Table Container Test

-
- - - - - - - - - - - - - - - -
NameStatusActions
Test Task -
- - -
-
Edit
-
-
- - - - diff --git a/test-due-date-reminders.mjs b/test-due-date-reminders.mjs deleted file mode 100644 index 1751350..0000000 --- a/test-due-date-reminders.mjs +++ /dev/null @@ -1,72 +0,0 @@ -#!/usr/bin/env node - -/** - * Test script to simulate due date reminders - * Creates a test project due in 3 days and runs the reminder script - */ - -import db from "./src/lib/db.js"; -import { addDays, format } from "date-fns"; - -async function createTestProject() { - try { - console.log("๐Ÿงช Creating test project due in 3 days..."); - - // Create a test contract first - const contractResult = db.prepare(` - INSERT INTO contracts (contract_number, contract_name, customer, date_signed) - VALUES (?, ?, ?, ?) - `).run('TEST-001', 'Test Contract', 'Test Customer', new Date().toISOString()); - - const contractId = contractResult.lastInsertRowid; - - // Create a test project due in 3 days - const dueDate = addDays(new Date(), 3); - const projectResult = db.prepare(` - INSERT INTO projects ( - contract_id, project_name, project_number, address, - finish_date, project_status - ) VALUES (?, ?, ?, ?, ?, ?) - `).run( - contractId, - 'Test Project - Due Soon', - '1/TEST-001', - 'Test Address 123', - dueDate.toISOString(), - 'in_progress_design' - ); - - console.log(`โœ… Created test project due on ${format(dueDate, 'yyyy-MM-dd')}`); - console.log("๐Ÿ”„ Running due date reminders script..."); - - // Run the reminders script - const { execSync } = await import('child_process'); - execSync('node send-due-date-reminders.mjs', { stdio: 'inherit' }); - - // Check if notifications were created - const notifications = db.prepare(` - SELECT * FROM notifications - WHERE type = 'due_date_reminder' - ORDER BY created_at DESC - LIMIT 5 - `).all(); - - console.log(`๐Ÿ“ข Found ${notifications.length} due date reminder notifications:`); - notifications.forEach(notif => { - console.log(` - ${notif.title}: ${notif.message.substring(0, 100)}...`); - }); - - // Clean up test data - console.log("๐Ÿงน Cleaning up test data..."); - db.prepare('DELETE FROM projects WHERE project_name = ?').run('Test Project - Due Soon'); - db.prepare('DELETE FROM contracts WHERE contract_number = ?').run('TEST-001'); - db.prepare('DELETE FROM notifications WHERE type = ? AND title LIKE ?').run('due_date_reminder', 'Projekt koล„czy siฤ™ za%'); - - console.log("โœ… Test completed successfully!"); - - } catch (error) { - console.error("โŒ Test failed:", error); - } -} - -createTestProject(); \ No newline at end of file diff --git a/test-edge-compatibility.mjs b/test-edge-compatibility.mjs deleted file mode 100644 index 0f85fbc..0000000 --- a/test-edge-compatibility.mjs +++ /dev/null @@ -1,83 +0,0 @@ -/** - * Test Edge Runtime compatibility for audit logging - */ - -// Test Edge Runtime detection -console.log("Testing Edge Runtime compatibility...\n"); - -// Simulate Edge Runtime environment -const originalEdgeRuntime = global.EdgeRuntime; -const originalNextRuntime = process.env.NEXT_RUNTIME; - -console.log("1. Testing in simulated Edge Runtime environment..."); -global.EdgeRuntime = "edge"; -process.env.NEXT_RUNTIME = "edge"; - -// Import the audit logging functions -const { logAuditEvent, getAuditLogs, AUDIT_ACTIONS, RESOURCE_TYPES } = - await import("./src/lib/auditLog.js"); - -// Test logging in Edge Runtime -logAuditEvent({ - action: AUDIT_ACTIONS.PROJECT_VIEW, - userId: "test-user", - resourceType: RESOURCE_TYPES.PROJECT, - resourceId: "test-project", - details: { test: "edge runtime test" }, -}); - -// Test querying in Edge Runtime -const logs = getAuditLogs({ limit: 10 }); -console.log(`Queried logs in Edge Runtime: ${logs.length} results`); - -console.log("2. Testing in simulated Node.js Runtime environment..."); -// Restore Node.js environment -delete global.EdgeRuntime; -delete process.env.NEXT_RUNTIME; - -// Test logging in Node.js Runtime -try { - logAuditEvent({ - action: AUDIT_ACTIONS.PROJECT_CREATE, - userId: "test-user", - resourceType: RESOURCE_TYPES.PROJECT, - resourceId: "test-project-2", - details: { test: "nodejs runtime test" }, - }); - console.log("Node.js runtime logging: โœ… Success"); -} catch (error) { - console.log("Node.js runtime logging: โŒ Error:", error.message); -} - -// Test querying in Node.js Runtime -try { - const nodeLogs = getAuditLogs({ limit: 10 }); - console.log( - `Node.js runtime querying: โœ… Success (${nodeLogs.length} results)` - ); -} catch (error) { - console.log("Node.js runtime querying: โŒ Error:", error.message); -} - -// Restore original environment -if (originalEdgeRuntime !== undefined) { - global.EdgeRuntime = originalEdgeRuntime; -} else { - delete global.EdgeRuntime; -} - -if (originalNextRuntime !== undefined) { - process.env.NEXT_RUNTIME = originalNextRuntime; -} else { - delete process.env.NEXT_RUNTIME; -} - -console.log("\nโœ… Edge Runtime compatibility test completed!"); -console.log("\nKey points:"); -console.log( - "- Edge Runtime: Logs to console, returns empty arrays for queries" -); -console.log("- Node.js Runtime: Full database functionality"); -console.log('- API routes are configured with runtime: "nodejs"'); -console.log("- Middleware avoids database operations"); -console.log("- Error handling prevents runtime crashes"); diff --git a/test-logged-in-flow.mjs b/test-logged-in-flow.mjs deleted file mode 100644 index 4e0b70d..0000000 --- a/test-logged-in-flow.mjs +++ /dev/null @@ -1,206 +0,0 @@ -// Test authenticated flow without external dependencies - -const BASE_URL = 'http://localhost:3000'; - -// Test data -const TEST_CREDENTIALS = { - email: 'admin@localhost.com', - password: 'admin123456' -}; - -// Helper function to extract cookies from response -function extractCookies(response) { - const cookies = response.headers.raw()['set-cookie']; - if (!cookies) return ''; - - return cookies - .map(cookie => cookie.split(';')[0]) - .join('; '); -} - -// Helper function to make authenticated requests -async function makeAuthenticatedRequest(url, options = {}, cookies = '') { - return fetch(url, { - ...options, - headers: { - 'Cookie': cookies, - 'Content-Type': 'application/json', - ...options.headers - } - }); -} - -async function testCompleteAuthenticatedFlow() { - console.log('๐Ÿ” Testing Complete Authenticated Flow\n'); - - try { - // Step 1: Get CSRF token from sign-in page - console.log('1๏ธโƒฃ Getting CSRF token...'); - const signinResponse = await fetch(`${BASE_URL}/auth/signin`); - const signinHtml = await signinResponse.text(); - - // Extract CSRF token (NextAuth.js typically includes it in the form) - const csrfMatch = signinHtml.match(/name="csrfToken" value="([^"]+)"/); - const csrfToken = csrfMatch ? csrfMatch[1] : null; - - if (!csrfToken) { - console.log('โŒ Could not extract CSRF token'); - return; - } - - console.log('โœ… CSRF token extracted'); - const initialCookies = extractCookies(signinResponse); - - // Step 2: Attempt login - console.log('\n2๏ธโƒฃ Attempting login...'); - const loginResponse = await fetch(`${BASE_URL}/api/auth/callback/credentials`, { - method: 'POST', - headers: { - 'Content-Type': 'application/x-www-form-urlencoded', - 'Cookie': initialCookies - }, - body: new URLSearchParams({ - csrfToken, - email: TEST_CREDENTIALS.email, - password: TEST_CREDENTIALS.password, - callbackUrl: `${BASE_URL}/projects`, - json: 'true' - }), - redirect: 'manual' - }); - - console.log(`Login response status: ${loginResponse.status}`); - - if (loginResponse.status === 200) { - const loginResult = await loginResponse.json(); - console.log('Login result:', loginResult); - - if (loginResult.url) { - console.log('โœ… Login successful, redirecting to:', loginResult.url); - } else if (loginResult.error) { - console.log('โŒ Login failed:', loginResult.error); - return; - } - } else if (loginResponse.status === 302) { - console.log('โœ… Login successful (redirect)'); - } else { - console.log('โŒ Login failed with status:', loginResponse.status); - const errorText = await loginResponse.text(); - console.log('Error response:', errorText.substring(0, 500)); - return; - } - - // Get session cookies - const sessionCookies = extractCookies(loginResponse) || initialCookies; - console.log('Session cookies:', sessionCookies ? 'Present' : 'Missing'); - - // Step 3: Test session endpoint - console.log('\n3๏ธโƒฃ Testing session endpoint...'); - const sessionResponse = await makeAuthenticatedRequest( - `${BASE_URL}/api/auth/session`, - {}, - sessionCookies - ); - - if (sessionResponse.ok) { - const session = await sessionResponse.json(); - console.log('โœ… Session data:', JSON.stringify(session, null, 2)); - } else { - console.log('โŒ Session check failed:', sessionResponse.status); - } - - // Step 4: Test protected pages - console.log('\n4๏ธโƒฃ Testing protected pages...'); - const protectedPages = ['/projects', '/contracts', '/tasks']; - - for (const page of protectedPages) { - const pageResponse = await makeAuthenticatedRequest( - `${BASE_URL}${page}`, - {}, - sessionCookies - ); - - if (pageResponse.ok) { - console.log(`โœ… ${page} - accessible`); - } else if (pageResponse.status === 302) { - console.log(`โš ๏ธ ${page} - redirected (status: 302)`); - } else { - console.log(`โŒ ${page} - failed (status: ${pageResponse.status})`); - } - } - - // Step 5: Test API endpoints - console.log('\n5๏ธโƒฃ Testing API endpoints...'); - const apiEndpoints = [ - { url: '/api/projects', method: 'GET' }, - { url: '/api/contracts', method: 'GET' }, - { url: '/api/tasks', method: 'GET' }, - { url: '/api/tasks/templates', method: 'GET' } - ]; - - for (const endpoint of apiEndpoints) { - const apiResponse = await makeAuthenticatedRequest( - `${BASE_URL}${endpoint.url}`, - { method: endpoint.method }, - sessionCookies - ); - - if (apiResponse.ok) { - const data = await apiResponse.json(); - console.log(`โœ… ${endpoint.method} ${endpoint.url} - success (${Array.isArray(data) ? data.length : 'object'} items)`); - } else if (apiResponse.status === 401) { - console.log(`โŒ ${endpoint.method} ${endpoint.url} - unauthorized (status: 401)`); - } else { - console.log(`โŒ ${endpoint.method} ${endpoint.url} - failed (status: ${apiResponse.status})`); - const errorText = await apiResponse.text(); - console.log(` Error: ${errorText.substring(0, 200)}`); - } - } - - // Step 6: Test creating data - console.log('\n6๏ธโƒฃ Testing data creation...'); - - // Test creating a project - const projectData = { - name: 'Test Project Auth', - description: 'Testing authentication flow', - deadline: '2025-12-31', - status: 'active' - }; - - const createProjectResponse = await makeAuthenticatedRequest( - `${BASE_URL}/api/projects`, - { - method: 'POST', - body: JSON.stringify(projectData) - }, - sessionCookies - ); - - if (createProjectResponse.ok) { - const newProject = await createProjectResponse.json(); - console.log('โœ… Project creation successful:', newProject.name); - - // Clean up - delete the test project - const deleteResponse = await makeAuthenticatedRequest( - `${BASE_URL}/api/projects/${newProject.id}`, - { method: 'DELETE' }, - sessionCookies - ); - - if (deleteResponse.ok) { - console.log('โœ… Test project cleaned up'); - } - } else { - console.log('โŒ Project creation failed:', createProjectResponse.status); - const errorText = await createProjectResponse.text(); - console.log(' Error:', errorText.substring(0, 200)); - } - - } catch (error) { - console.error('โŒ Test failed with error:', error.message); - } -} - -// Run the test -testCompleteAuthenticatedFlow(); diff --git a/test-logging.mjs b/test-logging.mjs deleted file mode 100644 index 1f72dc9..0000000 --- a/test-logging.mjs +++ /dev/null @@ -1,49 +0,0 @@ -import db from "./src/lib/db.js"; -import { - createProjectTask, - updateProjectTaskStatus, -} from "./src/lib/queries/tasks.js"; -import { getNotesByTaskId } from "./src/lib/queries/notes.js"; - -console.log("Testing automatic logging system...\n"); - -// Test 1: Create a new task and check if system note is created -console.log("Test 1: Creating a new task..."); -try { - const result = createProjectTask({ - project_id: 1, // Assuming project ID 1 exists - custom_task_name: "Test Task for Logging", - custom_description: "Testing automatic note creation", - custom_max_wait_days: 7, - priority: "high", - status: "pending", - }); - - const taskId = result.lastInsertRowid; - console.log(`โœ“ Task created with ID: ${taskId}`); - - // Check if system note was created - const notes = getNotesByTaskId(taskId); - console.log(`โœ“ Notes found: ${notes.length}`); - console.log("Notes:", notes); - - // Test 2: Update task status and check if system note is created - console.log("\nTest 2: Updating task status..."); - updateProjectTaskStatus(taskId, "in_progress"); - console.log("โœ“ Task status updated to in_progress"); - - // Check if new system note was created - const updatedNotes = getNotesByTaskId(taskId); - console.log(`โœ“ Notes after status update: ${updatedNotes.length}`); - console.log("Updated notes:", updatedNotes); - - // Clean up - delete test task - console.log("\nCleaning up test data..."); - db.prepare("DELETE FROM notes WHERE task_id = ?").run(taskId); - db.prepare("DELETE FROM project_tasks WHERE id = ?").run(taskId); - console.log("โœ“ Test data cleaned up"); -} catch (error) { - console.error("โŒ Error during testing:", error); -} - -console.log("\nTest completed."); diff --git a/test-mobile.html b/test-mobile.html deleted file mode 100644 index d443c31..0000000 --- a/test-mobile.html +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - Map Test - Mobile View - - - -
-
- Mobile View Test (400px width)
- Testing responsive behavior of the projects map -
- -
- - diff --git a/test-nextauth.mjs b/test-nextauth.mjs deleted file mode 100644 index b60efe2..0000000 --- a/test-nextauth.mjs +++ /dev/null @@ -1,47 +0,0 @@ -// Simple test for NextAuth endpoints -const BASE_URL = 'http://localhost:3000'; - -async function testNextAuthEndpoints() { - console.log('๐Ÿ” Testing NextAuth Endpoints\n'); - - // Test session endpoint - try { - const sessionResponse = await fetch(`${BASE_URL}/api/auth/session`); - console.log(`Session endpoint: ${sessionResponse.status} ${sessionResponse.statusText}`); - - if (sessionResponse.ok) { - const sessionData = await sessionResponse.json(); - console.log(`Session data: ${JSON.stringify(sessionData)}\n`); - } - } catch (error) { - console.log(`Session endpoint error: ${error.message}\n`); - } - - // Test providers endpoint - try { - const providersResponse = await fetch(`${BASE_URL}/api/auth/providers`); - console.log(`Providers endpoint: ${providersResponse.status} ${providersResponse.statusText}`); - - if (providersResponse.ok) { - const providersData = await providersResponse.json(); - console.log(`Providers: ${JSON.stringify(providersData, null, 2)}\n`); - } - } catch (error) { - console.log(`Providers endpoint error: ${error.message}\n`); - } - - // Test CSRF endpoint - try { - const csrfResponse = await fetch(`${BASE_URL}/api/auth/csrf`); - console.log(`CSRF endpoint: ${csrfResponse.status} ${csrfResponse.statusText}`); - - if (csrfResponse.ok) { - const csrfData = await csrfResponse.json(); - console.log(`CSRF token present: ${csrfData.csrfToken ? 'Yes' : 'No'}\n`); - } - } catch (error) { - console.log(`CSRF endpoint error: ${error.message}\n`); - } -} - -testNextAuthEndpoints().catch(console.error); diff --git a/test-notifications-api.mjs b/test-notifications-api.mjs deleted file mode 100644 index 6622a11..0000000 --- a/test-notifications-api.mjs +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/env node - -/** - * Test script to verify notifications API - */ - -async function testNotificationsAPI() { - try { - console.log("Testing notifications API..."); - - // Test unread count endpoint - const unreadResponse = await fetch('http://localhost:3001/api/notifications/unread-count'); - if (unreadResponse.ok) { - const unreadData = await unreadResponse.json(); - console.log("โœ… Unread count:", unreadData.unreadCount); - } else { - console.log("โŒ Unread count endpoint failed:", unreadResponse.status); - } - - // Test notifications list endpoint - const notificationsResponse = await fetch('http://localhost:3001/api/notifications'); - if (notificationsResponse.ok) { - const notificationsData = await notificationsResponse.json(); - console.log("โœ… Notifications fetched:", notificationsData.notifications.length); - console.log("Sample notification:", notificationsData.notifications[0]); - } else { - console.log("โŒ Notifications endpoint failed:", notificationsResponse.status); - } - - } catch (error) { - console.error("Error testing API:", error); - } -} - -testNotificationsAPI(); \ No newline at end of file diff --git a/test-notifications-working.mjs b/test-notifications-working.mjs deleted file mode 100644 index 61afb1a..0000000 --- a/test-notifications-working.mjs +++ /dev/null @@ -1,46 +0,0 @@ -#!/usr/bin/env node - -/** - * Test script to verify notifications are working - */ - -async function testNotifications() { - try { - console.log("Testing notifications system..."); - - // Test unread count endpoint (this should work without auth for now) - console.log("1. Testing unread count endpoint..."); - const unreadResponse = await fetch('http://localhost:3001/api/notifications/unread-count'); - - if (unreadResponse.status === 401) { - console.log("โœ… Unread count endpoint requires auth (expected)"); - } else if (unreadResponse.ok) { - const data = await unreadResponse.json(); - console.log("โœ… Unread count:", data.unreadCount); - } else { - console.log("โŒ Unread count endpoint failed:", unreadResponse.status); - } - - // Test notifications endpoint - console.log("2. Testing notifications endpoint..."); - const notificationsResponse = await fetch('http://localhost:3001/api/notifications'); - - if (notificationsResponse.status === 401) { - console.log("โœ… Notifications endpoint requires auth (expected)"); - } else if (notificationsResponse.ok) { - const data = await notificationsResponse.json(); - console.log("โœ… Notifications fetched:", data.notifications?.length || 0); - } else { - console.log("โŒ Notifications endpoint failed:", notificationsResponse.status); - } - - console.log("\n๐ŸŽ‰ Notification system test completed!"); - console.log("Note: API endpoints require authentication, so 401 responses are expected."); - console.log("Test the UI by logging into the application and checking the notification dropdown."); - - } catch (error) { - console.error("โŒ Error testing notifications:", error); - } -} - -testNotifications(); \ No newline at end of file diff --git a/test-project-api.mjs b/test-project-api.mjs deleted file mode 100644 index d17dc88..0000000 --- a/test-project-api.mjs +++ /dev/null @@ -1,27 +0,0 @@ -import fetch from "node-fetch"; - -async function testProjectAPI() { - const baseURL = "http://localhost:3000"; - - console.log("Testing project API endpoints...\n"); - - try { - // Test fetching project 1 - console.log("1. Fetching project 1:"); - const response = await fetch(`${baseURL}/api/projects/1`); - console.log("Status:", response.status); - - if (response.ok) { - const project = await response.json(); - console.log("Project data received:"); - console.log(JSON.stringify(project, null, 2)); - } else { - const error = await response.text(); - console.log("Error:", error); - } - } catch (error) { - console.error("Error testing API:", error.message); - } -} - -testProjectAPI(); diff --git a/test-project-creation.mjs b/test-project-creation.mjs deleted file mode 100644 index 14fc51c..0000000 --- a/test-project-creation.mjs +++ /dev/null @@ -1,43 +0,0 @@ -// Test project creation -const BASE_URL = "http://localhost:3001"; - -async function testProjectCreation() { - console.log("๐Ÿงช Testing project creation...\n"); - - try { - // First, login to get session - console.log("1. Logging in..."); - const loginResponse = await fetch( - `${BASE_URL}/api/auth/signin/credentials`, - { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - email: "admin@localhost.com", - password: "admin123456", - }), - } - ); - - console.log("Login response status:", loginResponse.status); - const loginResult = await loginResponse.text(); - console.log("Login result:", loginResult.substring(0, 200)); - - // Try a simple API call to see the auth system - console.log("\n2. Testing projects API..."); - const projectsResponse = await fetch(`${BASE_URL}/api/projects`); - console.log("Projects API status:", projectsResponse.status); - - if (projectsResponse.status === 401) { - console.log("โŒ Authentication required (expected for this test)"); - } else { - const projectsData = await projectsResponse.json(); - console.log("โœ… Projects API accessible"); - console.log("Number of projects:", projectsData.length); - } - } catch (error) { - console.error("โŒ Test failed:", error.message); - } -} - -testProjectCreation(); diff --git a/test-radicale-config.mjs b/test-radicale-config.mjs deleted file mode 100644 index df85ac3..0000000 --- a/test-radicale-config.mjs +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env node - -/** - * Test Radicale sync configuration - */ - -import { getRadicaleConfig, isRadicaleEnabled, generateVCard } from './src/lib/radicale-sync.js'; - -console.log('๐Ÿงช Testing Radicale Sync Configuration\n'); - -// Check if enabled -if (isRadicaleEnabled()) { - const config = getRadicaleConfig(); - console.log('โœ… Radicale sync is ENABLED'); - console.log(` URL: ${config.url}`); - console.log(` Username: ${config.username}`); - console.log(` Password: ${config.password ? '***' + config.password.slice(-3) : 'not set'}`); -} else { - console.log('โŒ Radicale sync is DISABLED'); - console.log(' Set RADICALE_URL, RADICALE_USERNAME, and RADICALE_PASSWORD in .env.local to enable'); -} - -console.log('\n๐Ÿ“ Testing VCARD Generation\n'); - -// Test VCARD generation -const testContact = { - contact_id: 999, - name: 'Jan Kowalski', - phone: '["123-456-789", "987-654-321"]', - email: 'jan.kowalski@example.com', - company: 'Test Company', - position: 'Manager', - contact_type: 'project', - notes: 'Test contact for VCARD generation', - is_active: 1, - created_at: new Date().toISOString() -}; - -const vcard = generateVCard(testContact); -console.log('Generated VCARD:'); -console.log('โ”€'.repeat(60)); -console.log(vcard); -console.log('โ”€'.repeat(60)); - -console.log('\nโœ… Test complete!'); diff --git a/test-safe-audit-logging.mjs b/test-safe-audit-logging.mjs deleted file mode 100644 index b9dbd02..0000000 --- a/test-safe-audit-logging.mjs +++ /dev/null @@ -1,82 +0,0 @@ -/** - * Test the safe audit logging in different runtime environments - */ - -console.log("Testing Safe Audit Logging...\n"); - -// Test 1: Import the safe module (should work in any runtime) -console.log("1. Testing safe module import..."); -try { - const { AUDIT_ACTIONS, RESOURCE_TYPES, logAuditEventSafe } = await import( - "./src/lib/auditLogSafe.js" - ); - console.log("โœ… Safe module imported successfully"); - console.log(` Available actions: ${Object.keys(AUDIT_ACTIONS).length}`); - console.log( - ` Available resource types: ${Object.keys(RESOURCE_TYPES).length}` - ); -} catch (error) { - console.log("โŒ Failed to import safe module:", error.message); -} - -// Test 2: Test in simulated Edge Runtime -console.log("\n2. Testing in simulated Edge Runtime..."); -global.EdgeRuntime = "edge"; -try { - const { logAuditEventSafe, AUDIT_ACTIONS, RESOURCE_TYPES } = await import( - "./src/lib/auditLogSafe.js" - ); - await logAuditEventSafe({ - action: AUDIT_ACTIONS.PROJECT_VIEW, - userId: null, // Use null to avoid foreign key constraint - resourceType: RESOURCE_TYPES.PROJECT, - resourceId: "test-123", - details: { test: "edge runtime" }, - }); - console.log("โœ… Edge Runtime logging successful (console only)"); -} catch (error) { - console.log("โŒ Edge Runtime logging failed:", error.message); -} - -// Test 3: Test in simulated Node.js Runtime -console.log("\n3. Testing in simulated Node.js Runtime..."); -delete global.EdgeRuntime; -try { - const { logAuditEventSafe, AUDIT_ACTIONS, RESOURCE_TYPES } = await import( - "./src/lib/auditLogSafe.js" - ); - await logAuditEventSafe({ - action: AUDIT_ACTIONS.PROJECT_CREATE, - userId: null, // Use null to avoid foreign key constraint - resourceType: RESOURCE_TYPES.PROJECT, - resourceId: "test-456", - details: { test: "nodejs runtime" }, - }); - console.log("โœ… Node.js Runtime logging successful (database + console)"); -} catch (error) { - console.log("โŒ Node.js Runtime logging failed:", error.message); -} - -// Test 4: Test constants accessibility -console.log("\n4. Testing constants accessibility..."); -try { - const { AUDIT_ACTIONS, RESOURCE_TYPES } = await import( - "./src/lib/auditLogSafe.js" - ); - - console.log("โœ… Constants accessible:"); - console.log(` LOGIN action: ${AUDIT_ACTIONS.LOGIN}`); - console.log(` PROJECT resource: ${RESOURCE_TYPES.PROJECT}`); - console.log(` NOTE_CREATE action: ${AUDIT_ACTIONS.NOTE_CREATE}`); -} catch (error) { - console.log("โŒ Constants not accessible:", error.message); -} - -console.log("\nโœ… Safe Audit Logging test completed!"); -console.log("\nKey features verified:"); -console.log("- โœ… No static database imports"); -console.log("- โœ… Edge Runtime compatibility"); -console.log("- โœ… Graceful fallbacks"); -console.log("- โœ… Constants always available"); -console.log("- โœ… Async/await support"); -console.log("\nThe middleware should now work without Edge Runtime errors!"); diff --git a/test-task-api.mjs b/test-task-api.mjs deleted file mode 100644 index 8412a48..0000000 --- a/test-task-api.mjs +++ /dev/null @@ -1,44 +0,0 @@ -// Test the project-tasks API endpoints - -async function testAPI() { - const baseURL = "http://localhost:3000"; - - console.log("Testing project-tasks API endpoints...\n"); - - try { - // Test 1: Check if users endpoint exists - console.log("1. Testing /api/project-tasks/users:"); - const usersResponse = await fetch(`${baseURL}/api/project-tasks/users`); - console.log("Status:", usersResponse.status); - if (usersResponse.ok) { - const users = await usersResponse.json(); - console.log("Users found:", users.length); - console.log("First user:", users[0]); - } else { - const error = await usersResponse.text(); - console.log("Error:", error); - } - - // Test 2: Try to create a task (this will fail without auth, but let's see the response) - console.log("\n2. Testing POST /api/project-tasks:"); - const taskData = { - project_id: 1, - task_template_id: 1, - priority: "normal", - }; - - const createResponse = await fetch(`${baseURL}/api/project-tasks`, { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify(taskData), - }); - - console.log("Status:", createResponse.status); - const responseText = await createResponse.text(); - console.log("Response:", responseText); - } catch (error) { - console.error("Error testing API:", error.message); - } -} - -testAPI(); diff --git a/test-task-sets.mjs b/test-task-sets.mjs deleted file mode 100644 index b9554cf..0000000 --- a/test-task-sets.mjs +++ /dev/null @@ -1,71 +0,0 @@ -#!/usr/bin/env node - -// Test script to verify task sets functionality -import { getAllTaskSets, createTaskSet } from './src/lib/queries/tasks.js'; -import initializeDatabase from './src/lib/init-db.js'; - -async function testTaskSets() { - console.log('Testing Task Sets Database Functions...\n'); - - try { - // Initialize database - initializeDatabase(); - - // Test 1: Get all task sets - console.log('1. Getting all task sets...'); - const taskSets = getAllTaskSets(); - console.log(`Found ${taskSets.length} task sets:`); - taskSets.forEach(set => { - console.log(` - ${set.name} (${set.task_category}):`, JSON.stringify(set)); - }); - - // Test 2: Create a new task set (design) - console.log('\n2. Creating design task set...'); - const designSetId = createTaskSet({ - name: 'Test Design Set', - description: 'Test task set for design tasks', - task_category: 'design', - templates: [] - }); - console.log(`Created task set with ID: ${designSetId}`); - - // Test 3: Create a construction task set - console.log('\n3. Creating construction task set...'); - const constructionSetId = createTaskSet({ - name: 'Test Construction Set', - description: 'Test task set for construction tasks', - task_category: 'construction', - templates: [] - }); - console.log(`Created task set with ID: ${constructionSetId}`); - - // Test 4: Try to create invalid task set (should fail) - console.log('\n4. Testing invalid task category (should fail)...'); - try { - const invalidSetId = createTaskSet({ - name: 'Invalid Set', - description: 'This should fail', - task_category: 'design+construction', - templates: [] - }); - console.log('โœ— Should have failed to create invalid task set'); - } catch (error) { - console.log('โœ“ Correctly rejected invalid task category:', error.message); - } - - // Test 5: Get all task sets again - console.log('\n5. Getting all task sets after creation...'); - const updatedTaskSets = getAllTaskSets(); - console.log(`Found ${updatedTaskSets.length} task sets:`); - updatedTaskSets.forEach(set => { - console.log(` - ${set.name} (${set.task_category})`); - }); - - console.log('\nโœ… All tests passed! Task sets functionality is working correctly.'); - - } catch (error) { - console.error('Test failed:', error.message); - } -} - -testTaskSets(); \ No newline at end of file diff --git a/test-user-tracking.mjs b/test-user-tracking.mjs deleted file mode 100644 index 319afdc..0000000 --- a/test-user-tracking.mjs +++ /dev/null @@ -1,27 +0,0 @@ -import { - getAllProjects, - getAllUsersForAssignment, -} from "./src/lib/queries/projects.js"; -import initializeDatabase from "./src/lib/init-db.js"; - -// Initialize database -initializeDatabase(); - -console.log("Testing user tracking in projects...\n"); - -console.log("1. Available users for assignment:"); -const users = getAllUsersForAssignment(); -console.log(JSON.stringify(users, null, 2)); - -console.log("\n2. Current projects with user information:"); -const projects = getAllProjects(); -console.log("Total projects:", projects.length); - -if (projects.length > 0) { - console.log("\nFirst project details:"); - console.log(JSON.stringify(projects[0], null, 2)); -} else { - console.log("No projects found."); -} - -console.log("\nโœ… User tracking implementation test completed!"); diff --git a/update-admin-username.js b/update-admin-username.js deleted file mode 100644 index 0886d35..0000000 --- a/update-admin-username.js +++ /dev/null @@ -1,28 +0,0 @@ -import Database from "better-sqlite3"; - -const db = new Database("./data/database.sqlite"); - -console.log("๐Ÿ”„ Updating admin username..."); - -try { - // Update admin username from email to simple "admin" - const result = db.prepare('UPDATE users SET username = ? WHERE username = ?').run('admin', 'admin@localhost.com'); - - if (result.changes > 0) { - console.log('โœ… Admin username updated to "admin"'); - } else { - console.log('โ„น๏ธ No admin user found with email "admin@localhost.com"'); - } - - // Show current users - const users = db.prepare("SELECT name, username, role FROM users").all(); - console.log("\nCurrent users:"); - users.forEach(user => { - console.log(` - ${user.name} (${user.role}): username="${user.username}"`); - }); - -} catch (error) { - console.error("โŒ Error:", error.message); -} finally { - db.close(); -} diff --git a/update-queries.ps1 b/update-queries.ps1 deleted file mode 100644 index dbb9512..0000000 --- a/update-queries.ps1 +++ /dev/null @@ -1,20 +0,0 @@ -$files = @( - "d:\panel\src\lib\queries\tasks.js", - "d:\panel\src\lib\userManagement.js" -) - -foreach ($file in $files) { - if (Test-Path $file) { - Write-Host "Updating $file..." - $content = Get-Content $file -Raw - $content = $content -replace "creator\.email as created_by_email", "creator.username as created_by_username" - $content = $content -replace "assignee\.email as assigned_to_email", "assignee.username as assigned_to_username" - $content = $content -replace "u\.email as created_by_email", "u.username as created_by_username" - $content = $content -replace "SELECT id, name, email, role", "SELECT id, name, username, role" - $content = $content -replace "name, email, role", "name, username, role" - Set-Content $file $content -NoNewline - Write-Host "Updated $file" - } -} - -Write-Host "All files updated!" diff --git a/verify-audit-fix.mjs b/verify-audit-fix.mjs deleted file mode 100644 index a8cc2b1..0000000 --- a/verify-audit-fix.mjs +++ /dev/null @@ -1,101 +0,0 @@ -import { - logAuditEvent, - getAuditLogs, - AUDIT_ACTIONS, - RESOURCE_TYPES, -} from "./src/lib/auditLog.js"; - -console.log("=== FINAL AUDIT LOGGING VERIFICATION ===\n"); - -async function verifyAuditLogging() { - try { - // 1. Check recent audit logs - console.log("1. Checking recent audit logs for user ID issues..."); - const recentLogs = await getAuditLogs({ limit: 10 }); - - console.log(`Found ${recentLogs.length} recent audit events:`); - recentLogs.forEach((log, index) => { - const userDisplay = log.user_id ? `user ${log.user_id}` : "NULL USER ID"; - console.log( - `${index + 1}. ${log.timestamp} - ${log.action} by ${userDisplay} on ${ - log.resource_type - }:${log.resource_id || "N/A"}` - ); - }); - - // 2. Count null user IDs - const allLogs = await getAuditLogs(); - const nullUserCount = allLogs.filter((log) => log.user_id === null).length; - const totalCount = allLogs.length; - const nullPercentage = ((nullUserCount / totalCount) * 100).toFixed(2); - - console.log(`\n2. Audit Log Statistics:`); - console.log(` Total audit logs: ${totalCount}`); - console.log(` Logs with NULL user_id: ${nullUserCount}`); - console.log(` Percentage with NULL user_id: ${nullPercentage}%`); - - // 3. Check distribution by action type - console.log(`\n3. Action distribution for NULL user_id logs:`); - const nullUserLogs = allLogs.filter((log) => log.user_id === null); - const actionCounts = {}; - nullUserLogs.forEach((log) => { - actionCounts[log.action] = (actionCounts[log.action] || 0) + 1; - }); - - Object.entries(actionCounts).forEach(([action, count]) => { - console.log(` ${action}: ${count} events`); - }); - - // 4. Test new audit event with valid user ID - console.log(`\n4. Testing new audit event with valid user ID...`); - await logAuditEvent({ - action: AUDIT_ACTIONS.LOGIN, - userId: "test-user-123", - resourceType: RESOURCE_TYPES.SESSION, - ipAddress: "127.0.0.1", - userAgent: "Test Agent", - details: { - test: "verification", - timestamp: new Date().toISOString(), - }, - }); - - // Verify the new event was logged correctly - const verificationLogs = await getAuditLogs({ limit: 1 }); - const latestLog = verificationLogs[0]; - - if (latestLog && latestLog.user_id === "test-user-123") { - console.log("โœ… SUCCESS: New audit event logged with correct user ID"); - } else { - console.log( - "โŒ FAILED: New audit event has incorrect user ID:", - latestLog?.user_id - ); - } - - // 5. Summary - console.log(`\n5. SUMMARY:`); - if (nullPercentage < 10) { - console.log("โœ… EXCELLENT: Very few NULL user IDs detected"); - } else if (nullPercentage < 30) { - console.log("โš ๏ธ GOOD: Some NULL user IDs but manageable"); - } else { - console.log("โŒ NEEDS ATTENTION: High percentage of NULL user IDs"); - } - - console.log(`\n6. RECOMMENDATIONS:`); - if (nullUserCount > 0) { - console.log( - " - The NULL user IDs are likely from before the fix was applied" - ); - console.log(" - New audit events should now log user IDs correctly"); - console.log(" - Monitor future logs to ensure the fix is working"); - } else { - console.log(" - All audit events have valid user IDs!"); - } - } catch (error) { - console.error("Verification failed:", error); - } -} - -verifyAuditLogging(); diff --git a/verify-project.mjs b/verify-project.mjs deleted file mode 100644 index c064555..0000000 --- a/verify-project.mjs +++ /dev/null @@ -1,7 +0,0 @@ -import { getProjectById } from "./src/lib/queries/projects.js"; - -console.log("Checking the created project with user tracking...\n"); - -const project = getProjectById(17); -console.log("Project details:"); -console.log(JSON.stringify(project, null, 2));