1. Replace serveStatic with Bun.file() to fix Content-Length: 0 bug
that caused Nginx to wait 12-30s per file.
2. Add section loader (spinner + 'Cargando...') while sections load.
3. Add AbortController to cancel previous fetch when switching menus.
4. Add credentials: 'same-origin' to ensure cookies are sent.
5. Add error handling for empty responses and HTTP errors.
Fixes: admin panel empty sections, 30s menu load, DOMException aborts.
Refs: production server tenerifeprop.es
Previously git reset removed symlinks (css, js, images, uploads)
which caused Nginx to return 404 for static assets.
Now deploy() recreates them after git sync.
Refs: production server, admin panel 404 fix
- Add getAdminProperties() to api.js with admin endpoint
- Update admin.js loadProperties() to use getAdminProperties
- Returns full dataset with admin filtering support
Refs: production admin panel
Previously admin.js used public /api/properties endpoint which lacks
admin-specific fields and returns published_only. New endpoint:
- Returns all properties (not just published)
- Supports status/type filtering
- Returns total count for pagination
- Protected by requireAdmin middleware
Fixes: admin properties table loading with full dataset.
Previously admin.js did not verify authentication on load.
Admin was accessible without login if user navigated directly.
Now checkAuth() is called before init() and redirects to /login
if user is not authenticated.
Refs: production server, admin panel security
Hono cors middleware with credentials: true requires origin to be
a concrete value, not '*'. Using origin callback that echoes
back the requesting origin satisfies browser CORS requirements
for fetch() with credentials: 'include'.
Fixes: API calls returning 401 on production because cookies
were not sent with cross-origin requests.
Refs: production server, admin dashboard
adminHtmlAuth middleware was intercepting ALL /admin/* requests before
serveStatic could serve component files (dashboard.html, properties.html, etc),
causing infinite 302 redirects to /login.
Solution: Disable server-side auth middleware for /admin/* HTML routes.
Client-side auth check in admin.js already redirects to /login.
API endpoints remain protected by requireAdmin middleware.
Refs: production server tenerifeprop.es
- Add adminHtmlAuth middleware that redirects unauthenticated users
to /login (302 redirect) for all /admin routes.
- Bypass static assets (css, js, images, fonts) without auth check.
- Add requireAuthRedirect middleware for future HTML auth needs.
- Fixes critical security issue where /admin was accessible without
authentication.
Refs: production server, issue #security-admin-redirect
- Add public/catalog.html with featured hero, quick categories, property grid
- Add conversion blocks: why-buy (6 cards), how-it-works (3 steps), CTA form, FAQ
- Register /catalog and /catalog.html routes in src/server/index.ts
- Update nav links in index.html and property.html to /catalog.html
- Add i18n support (ES/RU) for all new sections
- Deploy to Docker container
- admin.html: removed conflicting inline script, added api.js + admin.js
- admin.js: dynamic section loader with fetch, init navigates to hash
- api.js: credentials: 'include' for all admin requests
- propertyModal: added name attributes to all form fields, saveProperty onclick handler
- server/index.ts: added POST /api/analytics/event with daily aggregation
- server/validation.ts: removed min(6) from password for 401 on invalid credentials
- capability-index.yaml: added 11 MCP capability routes
- docker-compose-mcp.yml: created for MCP servers
- Removed duplicate main-wrapper div that caused large gap
- Changed topbar from sticky to fixed position
- Topbar now stays at top across all section loads
- Added margin-top to page-content to account for fixed topbar
- Updated sidebar toggle to also move topbar position
- Layout: sidebar (fixed) | topbar (fixed) | content (scrollable)
- Removed invalid chart.min.css link (Chart.js 4.x has no separate CSS)
- Fixed DataTables initialization:
- leadsTable: 7 columns, sort by date (column 3), no pagination
- fullLeadsTable: 10 columns, sort by date (column 6), with pagination
- Tables initialized separately to avoid column index mismatch
- Fixed Uncaught TypeError: aDataSort undefined
- Added overflow-x: hidden to .page-content
- Added max-width: 100% and overflow-x: hidden to .page-section
- This prevents FAQ accordion from overflowing outside content area
- FAQ now properly contained within right content panel
- Removed all custom .accordion styles that were causing layout issues
- FAQ now uses Bootstrap 5 default accordion styling
- Structure matches original exactly (no extra wrappers)
- FAQ is inside page-content > section-faq > accordion
- 5 FAQ questions with proper formatting
- No overflow issues with default Bootstrap styles
- Removed row > col-12 > card wrapper that was causing FAQ to overflow
- FAQ accordion now directly inside section, matching original structure
- Same pattern as Services section (direct children of section)
- Maintained 5 FAQ questions with proper styling
- Added card wrapper with proper padding for FAQ accordion
- Added 3 more FAQ questions (total 5):
- ¿Necesito cuenta bancaria española?
- ¿Cuánto tiempo tarda el proceso de compra?
- ¿Qué es el NIE y cómo lo obtengo?
- Added proper accordion styles:
- Rounded corners with box-shadow
- Proper spacing and colors
- Hover states for buttons
- Primary color for expanded items
- Centered accordion content
- Added fw-medium class to question text
- Added event.stopPropagation() to action buttons
- leadsTable (dashboard): 6 columns, sort by date (column 3)
- fullLeadsTable (leads section): 9 columns with checkbox, sort by date (column 6)
- Fixed JavaScript error from wrong column index
- Added separate initialization for each table
- Fixed DataTables order column index (was 6, table has 6 columns 0-5)
- Changed order to [[3, 'desc']] for date column
- Removed invalid chart.min.css link (Chart.js 4.x has no separate CSS)
- Changed loadDashboardData call to window.loadDashboardData
- Changed 'let charts = {}' to 'window.charts = {}'
- Replaced all 'charts.' references with 'window.charts.'
- This fixes charts not updating because the variable was scoped inside jQuery ready
- Now loadDashboardData can access charts after auth check
- Add propertyTypes to analytics/charts endpoint
- Make loadDashboardData globally accessible
- Call loadDashboardData after auth check
- Charts now properly update with real data:
- Performance chart (views/leads per month)
- Leads status chart
- Property types by city chart
- Traffic sources chart
- Top 5 properties chart
- Replace all /login.html redirects with /login in admin.html
- Remove /login.html route from server
- Update dashboard charts to load real data from API
- Add initCharts() and loadDashboardData() functions
- Remove static chart data and use dynamic API data
- Update stats counters to animate with real values
- Change redirect from /login.html to /login in admin.html
- Add /login.html route in server for backward compatibility
- Both /login and /login.html now serve the same login page
- Add analytics tables (analytics_events, analytics_daily)
- Add /api/admin/leads endpoint for lead listing
- Add /api/admin/analytics/overview and /api/admin/analytics/charts endpoints
- Seed database with 15 leads and 30 days of analytics data
- Update dashboard.html with:
- Animated counters for stats
- Performance chart (views/leads over 6 months)
- Leads status pie chart
- Property types bar chart
- Traffic sources doughnut chart
- Top properties horizontal bar chart
- Recent properties table with images
- Recent leads list with status badges
- Add API methods: getAnalyticsOverview(), getAnalyticsCharts()
The previous route '/admin' with serveStatic was catching all /admin/* requests
before component files could be served. Added explicit routes for each admin
component file (sidebar.html, topbar.html, etc.) to ensure they are served
correctly before the /admin SPA route.
- Restored original admin.html with full design (3251 lines)
- Created modular components in public/admin/
- Extracted CSS to public/css/admin.css
- Extracted JS to public/js/admin-components.js
- All 8 admin sections modularized
- Clean URLs working: /login, /admin
Components ready for future use when server routing is configured.
Current admin.html works standalone with full design preserved.
## Problem
- admin.html was not serving correctly (returned index.html instead)
- Routes for SPA were catching admin.html requests
## Solution
Added explicit routes before wildcard route:
- GET /admin.html → serve admin.html
- GET /login.html → serve login.html
- GET /login → serve login.html
- GET /admin → redirect to admin.html
## Tested
✅ login.html returns correct page (title: Iniciar Sesión)
✅ admin.html returns correct page (title: Panel de Administración)
✅ Login API works correctly
✅ Session management works
✅ Redirect after login to /admin.html works
Closes#28
- Replace hardcoded similar properties with dynamic API loading
- Similar properties now use correct slugs for navigation
- Fix admin password hash for authentication (admin123)
- Remove duplicate HTML footer tags from previous fix
The HTML files had malformed footer with duplicate script tags:
- </html> followed by empty <script></script> and navigation.js
- navigation.js exports switchLanguage with location.reload()
- This overwrites the inline switchLanguage function
- On page load, switchLanguage() → location.reload() → infinite loop
Removed duplicate footer from all HTML files.
The HTML files use inline styles (preserved from original) because
CSS extraction lost ~60% of styles. Tests now verify inline <style>
blocks exist with CSS variables.
- Restored src/server/index.ts with all API routes (was accidentally truncated)
- Fixed property card template to use 'property' variable consistently
- Added slug to all hardcoded properties for navigation
- Fixed static file serving for SPA routes with redirects
- All tests passing (24/24)
- API working correctly (JSON responses)
- Static CSS/JS files served with correct MIME types
- Fixed undefined 'prop' variable error
- All references now use 'property' variable consistently
- Added slug to all hardcoded properties for navigation
- Fixed template literals for proper variable substitution
- Restored full inline styles (~3100 lines CSS) that were lost during CSS extraction
- Removed malformed outer HTML wrapper
- Cleaned up indentation and formatting
- All styles now embedded directly in HTML for proper rendering
- Button styles, navbar, hero section, all components restored
- Fixed MIME type errors for CSS/JS in property/admin pages by adding redirect routes
- Updated HTML files to use absolute paths (/css/, /js/) instead of relative (css/, js/)
- Added redirect handlers for SPA static files to main static folders
- Preserved SPA functionality while fixing styling issues
- Moved static file serving before CSRF middleware
- Changed CSRF to only apply to /api/* routes
- Fixed MIME type issues for CSS and JS files
- Added explicit routes for .css and .js files