Notice [2025-05-22]: Full Codebase Refactor Incoming
We are planning a comprehensive refactor of the entire Logistics Portfolio codebase. This initiative will:
- Modernize all architectural patterns and enforce clean code principles
- Fully embrace object-oriented programming (OOP) best practices
- Address technical debt, improve maintainability, and enhance scalability
- Ensure every component, module, and utility is robustly documented and indexed
What to Expect:
- No area of the codebase is out of scope: all files, components, hooks, utilities, and styles will be reviewed and improved
- All changes will be fully commented, follow industry best practices, and be reflected in this README
- The refactor will be rolled out incrementally, with clear documentation for every update
Stay tuned for detailed migration guides and changelogs as the process unfolds.
- Major Change: All real authentication and backend/JWT logic has been removed from the app. The authentication provider now uses only dummy logic.
- How It Works:
- Logging in with the credentials below always works, regardless of backend/API/JWT state:
- Email:
[email protected] - Password:
password123
- Email:
- No backend, JWT, or session logic is required.
- Logging out simply clears the user state.
- Logging in with the credentials below always works, regardless of backend/API/JWT state:
- Intended Use: This mode is for demo, offline, QA, and development only. Not for production.
- Code Quality: All authentication code is fully commented, follows clean code architecture, and is OOP-friendly for maintainability.
- Where: See
components/auth-context.tsxfor implementation details.
-
Issues Fixed:
- Fixed 404 error on support page by correcting the navigation path to match the file structure
- Updated all client-side navigation paths to use the
/client/prefix to match the Next.js App Router file structure - Standardized the redirection logic after login and registration to properly navigate to
/client/dashboard - Added middleware to handle duplicate
/client/client/paths by redirecting to the login page
-
Technical Changes:
- Updated footerItems in client layout to use
/client/supportinstead of/support - Changed About page path from
/client-aboutto/aboutto match file structure - Modified login and register pages to redirect to
/client/dashboardinstead of/dashboard - Created a middleware.ts file to detect and redirect duplicate client paths
- Updated footerItems in client layout to use
-
Implementation Details:
- All navigation links now use paths that correctly match the file structure under
/app - The middleware uses Next.js built-in path detection to identify incorrect routes
- Changes maintain backward compatibility and follow Next.js best practices
- These changes ensure proper routing behavior as expected in Next.js App Router architecture
- All navigation links now use paths that correctly match the file structure under
-
Best Practices:
- In Next.js App Router, URL paths should match the directory structure under
/app - When nesting layouts (like in
/app/client/), all routes should include the parent segment prefix - Using middleware provides a clean solution for catching and redirecting invalid paths
- Standardizing redirect paths improves user experience and maintains consistent navigation flow
- In Next.js App Router, URL paths should match the directory structure under
- Issue: A TypeScript error occurred because a form submit handler (
(e: React.FormEvent<HTMLFormElement>) => Promise<void>) was assigned to a button'sonClickprop, which expects a mouse event handler (MouseEventHandler<HTMLButtonElement>). These event types are incompatible, leading to a type error. - Solution: The submit handler is now attached to the form's
onSubmitprop, and the button istype="submit"only, with noonClick. This ensures the correct event type is passed and resolves the error. - Best Practices: Always use
onSubmiton the form for submission logic andtype="submit"on the button. Avoid usingonClickfor form submission unless mouse event details are needed. All changes are fully commented and follow clean code, OOP, and documentation standards. - Reference: See
app/client/submit-shipment.mdfor a detailed explanation, code samples, and rationale.
- New Features:
- Users can now select the number of rows per page (5, 10, 20, 50, 100) directly from the Awaiting Shipment Table UI.
- Pagination controls now include "First", "Previous", "Next", and "Last" buttons for both desktop and mobile views.
- Changing the page size resets to the first page for optimal UX.
- Details:
- All pagination and page size logic is implemented with clean code and OOP best practices.
- All controls are robust against edge cases (e.g., disabling navigation when at the first/last page, empty datasets, etc).
- Inline comments document every line for clarity and maintainability.
- How to Use:
- Use the "Rows per page" dropdown above the table to change the page size at runtime.
- Use the navigation buttons to move between pages. The UI is fully responsive and accessible.
- Reference: See code comments in
AwaitingShipmentTable.tsxfor implementation and rationale.
- Issue: A parse error occurred due to an invalid closing tag (
</div{'>'}) inapp/client/components/AwaitingShipmentTable.tsx. - Root Cause: The fragment parser expected a corresponding closing tag for a JSX fragment, but encountered
</div{'>'}instead of</div>, breaking the fragment structure. - Fix: Replaced
</div{'>'}with the correct</div>and added an explanatory inline comment for maintainability. - Best Practices: This fix follows clean code, OOP, and documentation standards. All code is fully commented and indexed for future reference.
- Improvement: Pagination logic in
AwaitingShipmentTable.tsxis now extremely robust and professional. - Details:
- The "Next" and "Previous" buttons are disabled when at the last or first page, respectively. Users cannot advance past the last page or before the first page, even if the dataset changes size dynamically.
- Page counts are always accurate and reflect the filtered awaiting shipments.
- All pagination logic is clearly documented inline, following clean code and OOP best practices.
- All JSX fragment and closing tag issues were fixed as part of this update, ensuring bulletproof rendering and maintainability.
- Reference: See code comments in
AwaitingShipmentTable.tsxfor implementation and rationale.
A modern, responsive web application for showcasing logistics services, built with Next.js, React, and Tailwind CSS.
All markdown documentation (except for this README) is now located in the documentation/ folder at the project root. This keeps the codebase organized and maintainable. Update or add all future documentation in this folder for consistency.
Logistics Portfolio is designed to present logistics, warehousing, and delivery services in a visually appealing and interactive way. It features animated components, image preloading, and a clean, professional UI to help logistics businesses establish a strong online presence.
This project uses custom web components such as <dotlottie-player>. To enable TypeScript and JSX support for these elements:
- All custom elements are declared in
custom-elements.d.tsat the project root. - This ensures TypeScript recognizes custom tags in
.tsxfiles and prevents JSX type errors. - The interface for each custom element can be extended with specific attributes for better type safety.
- The file is fully commented and follows clean code/OOP best practices for maintainability.
If you see an error like:
Property 'dotlottie-player' does not exist on type 'JSX.IntrinsicElements'.
Follow these steps:
-
Ensure
custom-elements.d.tsexists at the project root and contains the correct declaration for your custom element:declare global { namespace JSX { interface IntrinsicElements { "dotlottie-player": React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement> & { src?: string; autoplay?: boolean; loop?: boolean; mode?: string; [key: string]: any; }; } } }
-
Make sure the file is named
custom-elements.d.ts(not.ts) and does not includeexport {}at the top. -
Restart your IDE/TypeScript server to ensure the new types are picked up.
-
If the error persists, confirm that your
tsconfig.jsonincludes the root directory or the file path for type declarations.
Best Practice:
- Centralize all custom element typings in
custom-elements.d.tsfor maintainability. - Extend the interface as you add more custom web components.
- Document all changes inline and in this README.
- The Lottie animation in the AwaitingShipmentDetail modal now always plays reliably.
- This is achieved by forcing a remount of the
<dotlottie-player>web component using aresetKeyprop passed toLottiePlayerSection. - The script for the player is loaded only once, and the animation is reset on each modal open for a seamless user experience.
- All code follows OOP and clean code best practices, with thorough inline documentation.
- All TypeScript and linter errors, including duplicate component definitions, have been resolved.
- See
AwaitingShipmentDetail.tsxfor implementation details and comments.
- The Awaiting Shipments dashboard renders exactly three cards: Total Awaiting (green), Pending (yellow), and Received (blue).
- All status cards are dynamically sourced from the shared
SHIPMENT_STATUSESconstant inlib/logistics-statuses.ts. - Card colors are mapped via a single color map object for maintainability and professional UX.
- The "Total Awaiting" card uses a green color scheme for positive emphasis, as requested.
- If you add or change statuses in
SHIPMENT_STATUSES, the dashboard will automatically reflect those changes (extensible, no hardcoding). - All props for cards are type-safe and guaranteed, eliminating runtime or TypeScript errors.
- Code is modular, commented, and follows OOP and clean code architecture best practices.
- Accepts a
colorprop (Tailwind classes) for status-based color coding. - Uses a clean, professional layout with responsive design.
- All logic is fully commented inline for maintainability and onboarding.
- Follows OOP and clean code principles for reuse and extensibility.
- All shipment status logic is driven by
documentation/statuscodes.md. - Only the following statuses are valid: Pending, Received, In Transit, Arrived, Delivered.
- Awaiting Shipments view only shows: Pending, Received, In Transit, Arrived (never Delivered).
- Statuses are color-coded using a single source of truth in
lib/status-color-map.ts, following the color scheme instatuscodes.md. - All components and business logic use the constants from
lib/logistics-statuses.tsandstatuscodes.mdfor consistency and maintainability. - See
documentation/statuscodes.mdfor full documentation, color mapping, and developer guidance.
- Renders shipment statuses dynamically from
SHIPMENT_STATUSES(never hardcoded). - Statuses are color-coded and include tooltips for descriptions, improving user experience and accessibility.
- Uses
@tanstack/react-tablefor scalable table logic andreact-windowfor virtualization, supporting thousands of rows efficiently. - Table is fully responsive: shows table on desktop, cards on mobile.
- All code is modular, type-safe, and documented inline.
- Every component and function is fully commented for clarity and maintainability.
- All logic is modular, DRY, and type-safe for scalability and professional development.
- Status rendering and color logic are centralized for easy updates and onboarding.
- Color coding provides instant, intuitive feedback for shipment statuses.
- Dynamic rendering ensures the UI always matches the business logic and status config.
- All changes are maintainable, extensible, and easy for new developers to understand (see code comments and this section).
- All shipment tracking now uses a secure, random, unguessable public tracking code:
trackingCode(e.g.,SHIP-7G9X2A). - Internal shipment IDs remain linear/incrementing for backend/database use, but are never exposed to users.
-
All dummy shipment data for
/api/awaiting-shipmentsis now generated programmatically using thegenerateDummyShipmentsfunction inapp/api/awaiting-shipments/route.ts. -
All legacy, hardcoded shipment objects have been removed for maintainability, clarity, and clean code architecture.
-
The generator produces objects that match the API contract and are randomized for realistic testing.
-
All code is modular, OOP-friendly, and fully commented for maintainability.
-
This approach ensures the codebase is scalable, DRY, and easy to update as business requirements evolve.
-
This approach ensures security (codes can't be guessed or brute-forced), scalability, and professional UX.
-
All logic is fully commented and documented for maintainability and best practices.
The AwaitingShipmentTable component is a highly scalable, production-grade React table for displaying large datasets of shipments. It is fully typed with TypeScript, supports API integration, and handles loading and error states. The table is virtualized for performance using react-window and uses @tanstack/react-table for table logic. All code follows clean code architecture, OOP principles, and is fully commented.
Features:
- Accepts data from a real API or static source
- Handles loading and error UI states
- Virtualized rendering for large datasets
- Responsive: Table on desktop, cards on mobile
- Modular, maintainable, and fully documented
interface AwaitingShipmentTableProps {
---
### 🔄 Switching from Dummy Data to Real API (Production Integration)
The Awaiting Shipments API is currently configured to always return dummy data for development and demo purposes.
**When your backend is ready, update the handler as follows:**
```typescript
// /app/api/awaiting-shipments/route.ts
import { NextResponse } from 'next/server';
const DUMMY_SHIPMENTS = [ /* ...dummy data... */ ];
export async function GET() {
const devMode = process.env.DEV_MODE === 'true';
const realApiUrl = process.env.REAL_AWAITING_SHIPMENTS_API_URL;
// Use real API if not in dev mode and the URL is set
if (!devMode && realApiUrl) {
try {
const response = await fetch(realApiUrl);
if (!response.ok) throw new Error('Failed to fetch from real API');
const data = await response.json();
if (!Array.isArray(data)) throw new Error('API did not return an array');
return NextResponse.json(data);
} catch (e) {
// Fallback to dummy data if the real API fails
return NextResponse.json(DUMMY_SHIPMENTS);
}
}
// Default to dummy data for development or missing API URL
return NextResponse.json(DUMMY_SHIPMENTS);
}How to Enable Real API:
- Set
DEV_MODE=falsein your.envor deployment environment. - Set
REAL_AWAITING_SHIPMENTS_API_URLto your backend endpoint. - Replace the
GEThandler in/app/api/awaiting-shipments/route.tswith the snippet above. - Restart your server.
This ensures a seamless transition from dummy data to real backend integration with zero code changes elsewhere in your app.
-
Refactored
AwaitingShipmentTableto use the new column definition API from@tanstack/react-tablev8+. -
Migrated all column objects from using
Header(capital H) toheader(lowercase h), and fromaccessortoaccessorKey(for direct property access) oraccessorFn(for computed values). -
All columns are now fully commented and typed, following clean code architecture and OOP best practices.
-
This resolves type errors and ensures compatibility with the latest table library version.
-
The
ProfessionalCardSlidercomponent now supports a configurableslideIntervalprop for carousel auto-advance. -
The default interval is set by the
DEFAULT_SLIDE_INTERVALconstant (30 seconds), but you can override it for any instance. -
This follows clean code architecture and OOP best practices: the interval is clearly named, documented, and easily adjustable.
-
All logic is fully commented and type-safe for maintainability.
Usage Example:
import ProfessionalCardSlider from "@/components/professional-hero";
// Use default interval (30s)
<ProfessionalCardSlider />
// Use a custom interval (e.g., 10 seconds)
<ProfessionalCardSlider slideInterval={10000} />Prop:
slideInterval?: number— Interval in milliseconds between slides (default: 30000)
- The sidebar/footer now uses a dedicated Logout button instead of a navigation link.
- The button directly calls the
logoutfunction from the authentication context (useAuth), ensuring best practices for security, SSR, and clean code. - Button is styled consistently with sidebar items and is fully commented for maintainability.
- This change prevents navigation to a
/logoutroute and ensures logout logic is always executed. - See
app/client/layout.tsxfor implementation details.
- The sidebar now uses the
useIsMobilecustom React hook (seehooks/use-mobile.tsx) to detect mobile viewports. - When navigating via the sidebar on mobile, the sidebar automatically closes for a seamless user experience.
- This logic is encapsulated in a reusable hook for clean code, OOP, and maintainability.
Overview:
For local development and QA, the app provides a built-in toggle to switch between real backend authentication and in-memory dummy authentication. This enables seamless testing of all authentication flows, even when the backend API is unavailable or when you want to demo the app without real user accounts.
How It Works:
- By default, the app uses real authentication (backend API).
- To use dummy authentication (for local testing, demos, or offline development):
- Open your browser's developer console.
- Run:
localStorage.setItem('auth_mode', 'dummy') - Refresh the page. The app will now use the dummy user for authentication.
- To switch back to real authentication:
- Run:
localStorage.setItem('auth_mode', 'real') - Refresh the page.
- Run:
- No UI toggle is provided for switching modes. This is intentional for production safety and to keep the UI clean.
Dummy User for Testing:
- Only one dummy user is available for development and QA:
- Email:
[email protected] - Password:
password123
- Email:
- Dummy user avatar and name are realistic for UI prototyping.
Session Expiration:
- Dummy sessions expire after 2 hours by default (configurable in code).
- If the session is expired (e.g., after a long browser pause), you will be logged out automatically on refresh.
- Session expiration is managed via a timestamp in the cookie (no backend required).
Behavior in Each Mode:
- Real:
- Login, logout, and session hydration all use the backend API.
- All security and redirect logic is enforced as in production.
- Dummy:
- Log in with any of the dummy user credentials above. The session is managed in memory and persisted via cookie until expiration or logout.
- Logging out clears the dummy session and cookie.
- Useful for demos, UI/UX testing, and offline development.
Testing Checklist:
- Switch the authentication mode via
localStoragecommands and verify:- In Dummy mode, you can log in and out using any dummy credentials, and the app behaves as if a real user is logged in (including role-based UI if implemented).
- In Real mode, only real backend authentication works.
- Switching modes instantly updates the app's authentication state.
- After 2 hours (or configurable duration), dummy sessions expire and require re-login.
- Always use Real mode for production and QA that require backend validation.
Troubleshooting:
- If you do not see the toggle, ensure you are running in development mode (
npm run devoryarn dev). - If you cannot log in with the dummy credentials, ensure you have selected "Dummy" mode.
- If you are unexpectedly logged out in dummy mode, your session may have expired.
Security Note:
- The dummy authentication mode and toggle are only available in development. They are never exposed in production builds.
Future Enhancements:
- A dev-only UI for editing/adding dummy users on-the-fly for rapid prototyping.
- More advanced session controls (e.g., warning before expiration, manual session extension).
- Example usage in a component:
import { useIsMobile } from "@/hooks/use-mobile"; const isMobileView = useIsMobile(); // ... if (isMobileView) setIsOpen(false);
- Chatbot Button Temporarily Disabled
- The Chatbot button (
ChatbotButtonWrapper) inapp/layout.tsxis currently commented out for future updates. - To re-enable, simply uncomment the relevant line in the layout file.
- This approach keeps the codebase clean while allowing easy restoration of the feature when ready.
- The Chatbot button (
- Global Loader Architecture:
- All loading UI is now managed by a single global loader (
AppLoaderWrapper). - The loader listens to the global loading state from
AuthProvider(via theuseAuthhook). - All page/component-level loaders have been removed for consistency and maintainability.
- The loader is only displayed during authentication/user hydration or other global loading events.
- This ensures a professional, non-redundant, and cohesive user experience.
- See the
AppLoaderWrapperandAuthProvidercomponents for implementation details.
- All loading UI is now managed by a single global loader (
- Removed all local/component-level loading state and loader UI from pages and components (e.g.,
AppShell). - Refactored
AppLoaderWrapperto consume loading state fromAuthProvideronly. - Updated all documentation and tests to reflect the new architecture.
- To trigger the global loader, set the
loadingstate inAuthProvidertotrue. - The loader will automatically appear and hide based on the global loading state.
- No component/page should manage its own loading UI—use the context instead.
-
Automated tests are provided in
tests/global-loader.test.tsx. -
These tests ensure:
- The loader is visible when the global loading state is
true. - The loader is hidden and content is visible when loading is
false. - No duplicate loaders appear from local/component state.
- The loader is visible when the global loading state is
-
Run tests with
npm testoryarn test(see package.json for details). -
All tests follow clean code and OOP best practices.
-
Global Theming:
- The
ThemeProviderfromnext-themesis now applied only at the root layout (app/layout.tsxorapp/client/layout.tsx). - This ensures that the theme context is shared globally across the entire application, allowing the theme toggle button in the header to update the theme everywhere.
- Do not wrap nested components (such as
AppShell) in anotherThemeProvider; doing so would create a new context and break global theme switching. - The
ModeSwitchercomponent has been removed fromAppShell. - All theme toggling is now managed via the header's
ThemeTogglecomponent, which uses the global theme context.
- The
-
AuthProvider isolation: When testing multiple AuthProvider contexts, render each provider in a separate tree to avoid state leakage. See
auth-context.extra.test.tsxfor an example. -
ChatbotWindow tests: Use React Testing Library's built-in queries (
getByTestId,getByText) from the render result instead of custom DOM helpers. This ensures tests are robust and scoped correctly. -
All chatbot API/network failures will show the following error message in the chat window:
Failed to connect to chatbot. Please try again.
-
This message is set in the
ChatbotWindowcomponent for consistency and to ensure tests can reliably check for error state rendering. -
Responsive design for all devices
-
Animated hero sections and cards
-
Preloading and smooth transitions
-
Dark/light mode support
-
Custom cursor and scroll progress effects
-
Modular, reusable React components
-
AI Chatbot (Nana) for LogisticsFuture: Professional, branded, and privacy-conscious assistant for air freight between Ghana and the US
- Next.js
- React
- TypeScript
- Tailwind CSS
- Three.js (for 3D scenes)
- PNPM (package manager)
To enable dummy login fallback for development or testing, set the following in your .env file:
NEXT_PUBLIC_ENABLE_DUMMY_LOGIN=true- When enabled, logging in with the credentials below will always succeed (even if the backend API is down):
- Email:
[email protected] - Password:
password123
- Email:
- In production, set
NEXT_PUBLIC_ENABLE_DUMMY_LOGIN=falseor remove the line for security.
- Dummy login fallback is only triggered if:
NEXT_PUBLIC_ENABLE_DUMMY_LOGINis set totrue.- The credentials are exactly
[email protected]/password123. - The backend API is unavailable or returns an error.
- All other logins require a real backend response.
Unit tests for the authentication logic are provided in tests/auth-context.test.tsx.
To run the tests:
pnpm test
yarn test
# or
npm testThese tests cover:
- Real API login
- Dummy login fallback (with and without the flag)
- Rejection for wrong credentials or when the flag is off
- Node.js (v18+ recommended)
- PNPM (or npm/yarn)
git clone https://github.com/kaeytee/logistics-portfolio.git
cd logistics-portfolio
pnpm installpnpm devVisit http://localhost:3000 to view the app.
pnpm build
pnpm startcomponents/ # Reusable React components
app/ # Next.js app directory (pages, layouts)
public/ # Static assets (images, models, avatars)
styles/ # Global and component styles
lib/ # Utility functions (including chatbot logic)
hooks/ # Custom React hooks
- If OpenRouter is unavailable or fails, the chatbot now uses a local fallback script (
lib/my-ai-fallback.ts). - The fallback is rules-based by default, but you can extend
MyAIFallbackwith your own AI model, local inference server, or custom logic. - All fallback logic is fully OOP, commented, and ready for developer extension.
- See
lib/chatbot.tsfor how the fallback is integrated and tiered with OpenRouter.
To implement FAQ management in your admin app (recommended for professional operations):
- CRUD Operations:
- Allow admins to Create, Read, Update, and Delete FAQ entries (question/answer pairs) via a secure UI.
- Store FAQs in a backend database (e.g., PostgreSQL, MongoDB, or even a flat file for MVP).
- Use OOP and clean code: encapsulate FAQ logic in service and repository classes, with strict validation and error handling.
- Add audit logs and user attribution for all edits.
- Validation & UX:
- Validate for duplicate questions, required fields, and professional language.
- Preview FAQ entries as they will appear to users (including HTML rendering for links).
- Integration with Embeddings:
- On FAQ create/update/delete, trigger the embedding regeneration pipeline automatically (see CI/CD below).
- Optionally, provide a "Regenerate Embeddings" button in the admin UI that calls an API endpoint to run the embedding script.
- API Design:
- Expose RESTful or GraphQL endpoints for FAQ CRUD, secured with admin authentication.
- Provide endpoints for fetching all FAQs and for triggering embedding regeneration (POST /admin/faq/embeddings/rebuild).
- Best Practices:
- Use optimistic UI updates and error boundaries.
- Document the admin workflow and onboarding in your internal docs.
- Why: Keep your team informed of knowledge base updates, embedding regenerations, and potential issues.
- How:
- Integrate with Slack, Discord, or email using GitHub Actions or your backend.
- Example: Add a GitHub Actions step after embedding regeneration:
- name: Notify Slack of embedding update uses: slackapi/[email protected] with: payload: '{"text":"FAQ embeddings updated and deployed! :robot_face:"}' env: SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
- For email, use
actions/send-mail@v1or trigger a custom webhook to your backend. - For Discord, use a webhook notification step.
- Best Practice:
- Notify on both success and failure of embedding regeneration and deployment.
- Include a link to the PR, commit, or deployment preview in the notification.
- Branch Protection & PR Checks:
- Require all FAQ/embedding changes to go through Pull Requests with code review.
- Add a CI check to ensure
company-faq-embeddings.jsonis always up-to-date withcompany-faq.json.
- Preview Deployments:
- Use Vercel, Netlify, or similar to deploy preview branches for every PR.
- Test FAQ changes and chatbot responses in a live preview before merging.
- Notification Hooks:
- Integrate Slack/Discord/email notifications for PR merges, deployment failures, or embedding regeneration issues.
- Secrets Management:
- Store all sensitive tokens (Slack, email, etc.) in CI/CD secrets, never in code.
- Onboarding:
- Document this workflow in your internal onboarding guide and README for new developers/admins.
- HuggingFace and Python offer state-of-the-art language models for generating semantic embeddings.
- This approach is industry-standard for knowledge-augmented chatbots, even in Node.js/Next.js projects.
- Python is only used for offline data processing — never in your production web server or client.
- Create a virtual environment:
python3 -m venv .venv source .venv/bin/activate - Install dependencies:
pip install -r requirements.txt
- This keeps Python packages isolated from your system and Node.js dependencies.
- Edit your FAQ:
- Update
lib/data/company-faq.jsonwith new Q&A pairs. - Authoring Guidelines:
- Write clear, concise, and professional questions and answers.
- Include both common and advanced (future-facing) questions users might ask.
- Cover operational, technical, and customer support topics.
- Use proper grammar and company branding/tone.
- Example:
{ "question": "What new routes will LogisticsFuture offer in the future?", "answer": "We are always expanding! For future route announcements, please sign up for our newsletter or check our Updates page." }
- Update
- Regenerate embeddings (manual workflow):
- With your virtual environment activated, run:
python scripts/generate_faq_embeddings.py
- This creates/updates
lib/data/company-faq-embeddings.json.
- With your virtual environment activated, run:
- No server restart needed:
- Your Next.js app will use the updated knowledge base automatically.
- Add an npm script to package.json:
"scripts": { "generate-faq-embeddings": "source .venv/bin/activate && python scripts/generate_faq_embeddings.py" }
- Now you (or your CI) can run:
npm run generate-faq-embeddings
- Now you (or your CI) can run:
- CI/CD integration:
- In your pipeline (GitHub Actions, GitLab CI, etc.), add a step to:
- Set up Python and dependencies
- Run the embedding script after FAQ edits
- Commit or deploy the updated
company-faq-embeddings.json
- In your pipeline (GitHub Actions, GitLab CI, etc.), add a step to:
- Best Practice:
- Always regenerate embeddings after FAQ changes, before deploying to production.
- To see the embedding for a specific question:
python scripts/generate_faq_embeddings.py --query "How do I track my shipment?"
- Keep all Python scripts in the
scripts/folder. - Never run Python scripts from the client/browser.
- Document this workflow for new developers (see this section for onboarding).
- You can upgrade to a pure Node.js embedding solution later if desired.
- Using Python for embedding generation and Node.js for serving is common in production AI/chatbot systems.
- This separation ensures maintainability, performance, and access to the best models.
- All chatbot API/network failures display a clear error message:
Failed to connect to chatbot. Please try again. - Backend configuration errors are surfaced in the chat UI with a special warning and logged to the browser console for developer insight.
- Full OpenRouter API responses are logged server-side for debugging.
- All error and fallback handling is documented in
components/ChatbotWindow.tsxandlib/chatbot.ts.
- Users can copy any message, expand/collapse long responses, and provide thumbs up/down feedback on bot replies.
- The chat UI is fully accessible (keyboard navigation, escape key closes window, outside click handler via OOP class).
- Conversation history is persisted locally and can be cleared or exported by the user.
- All agent and chatbot logic is fully OOP and commented for maintainability.
- Extend the AI agent in
lib/ai-agent.tsfor new discovery logic or LLM plugins. - All messages, errors, and API interactions are testable and observable for robust CI/CD workflows.
- Clean separation of concerns: UI, agent, and API logic are modular and independently testable.
This app includes an AI-powered chatbot named Nana for LogisticsFuture, available on all pages via a floating button. Nana provides:
- Professional, time-based greeting and service introduction
- Answers about air freight services between Ghana and the US (and back)
- Out-of-scope queries are redirected to customer care
- Conversation history (10 messages, localStorage)
- Newsletter sign-up prompt for updates on new routes/services
- Privacy-conscious responses (no personal data stored beyond session)
- Clear AI identity: custom for LogisticsFuture, powered by OpenAI
- Professional avatar and branding
The AI chatbot (Nana) now features dynamic app discovery and self-awareness via a custom agent. Nana can answer questions about:
- App routes (pages, dynamic routes, parameters)
- Components (UI, logic, utilities)
- API endpoints (REST, Next.js API routes)
This is achieved through a clean, OOP-based agent architecture, making the chatbot a true in-app assistant for both users and developers.
lib/ai-agent.ts: ImplementsChatbotAIAgent,RouteIndexer, andCodebaseSearcher.- Indexes all
/approutes (static/dynamic),/components,/lib, and/app/api. - Finds and returns relevant code artifacts by user query (e.g., "find login page", "where is the sidebar component?").
- Indexes all
lib/chatbot.ts:- Exports
getChatbotResponse, which first uses the agent for discovery, then falls back to LLM (OpenRouter) for general queries.
- Exports
app/api/chatbot/route.ts:- Handles all chatbot API requests using the new dynamic logic.
- End Users:
- Ask Nana about any page, component, or API (e.g., "Where is the registration page?", "Show me the sidebar component.").
- Nana will respond with direct file paths, route info, or lists of matching components/APIs.
- Developers:
- Extend the agent in
lib/ai-agent.tsfor new codebase search logic or plugin LLMs. - The system is fully OOP and documented for maintainability.
- Extend the agent in
API URL Construction:
- All API calls now use a robust utility in
lib/api.tsthat constructs the API URL usingNEXT_PUBLIC_API_BASE_URLif set, or defaults to a relative path (e.g.,/api/auth/login) if not set. - This prevents errors like
/undefined/api/auth/loginon Vercel and ensures compatibility for both local and cloud deployments.
How it works:
// In lib/api.ts
const baseUrl = process.env.NEXT_PUBLIC_API_BASE_URL || "";
const url = `${baseUrl}${endpoint}`.replace(/([^:]\/)\/+/, "$1");Deployment Instructions:
- On Vercel:
- If your frontend and backend are deployed together (Next.js fullstack), you may leave
NEXT_PUBLIC_API_BASE_URLunset or set it to an empty string. - If using a separate backend, set
NEXT_PUBLIC_API_BASE_URLto your backend's URL (e.g.,https://api.yoursite.com).
- If your frontend and backend are deployed together (Next.js fullstack), you may leave
- Locally:
- Set
NEXT_PUBLIC_API_BASE_URLin.envas needed, or leave unset for default relative API routing.
- Set
Fallback Logic:
- The
fetchWithFallbackutility includes a fallback to dummy data for development/testing, following clean code and OOP best practices.
// Example usage of fetchWithFallback
import { fetchWithFallback } from './lib/api';
const endpoint = '/api/data';
const dummyData = { key: 'value' }; // Example dummy data
async function fetchData() {
const data = await fetchWithFallback(endpoint, dummyData);
console.log(data); // Logs fetched data or dummyData if the fetch fails
}
fetchData();
---
#### Example Queries
- `find login page` → Returns route and file path for the login page.
- `show me the AuthProvider` → Lists the file(s) where `AuthProvider` is implemented.
- `where is the registration API?` → Returns the relevant API endpoint(s).
#### Clean Code & Extensibility
- Every agent and chatbot class/function is fully commented.
- The architecture supports future LLM upgrades and plugin integrations.
- All changes are indexed and discoverable for future developer onboarding.
### Setup
1. Install dependencies:
```bash
pnpm add axios dompurify react-helmet-async
pnpm add -D jest @testing-library/react @testing-library/jest-dom @testing-library/user-event- Add to
.env:NEXT_PUBLIC_OPEN_ROUTER_API_URL=https://openrouter.ai/api OPEN_ROUTER_API_KEY=your_openrouter_api_key
- Deploy with these env vars set in Vercel.
- Place your avatar images in the
public/directory asavatar-nana.pngandavatar-user.pngfor best results.
- Click the chat button to open the chatbot.
- Ask about air freight, tracking, or company info.
- For out-of-scope queries, Nana will direct you to customer care or invite you to sign up for the newsletter.
- Nana will always use a professional tone and respect your privacy.
Issue:
- Attempting to install new packages (e.g.,
js-cookie) may fail due to strict npm peer dependency conflicts betweenreact,react-day-picker, anddate-fns. - Example error:
Cannot find module 'js-cookie' or its corresponding type declarations. - The project currently uses
[email protected],[email protected], and[email protected], which are not all mutually compatible.
Workaround:
-
To install new dependencies (like
js-cookie), use the--legacy-peer-depsflag:npm install js-cookie @types/js-cookie --legacy-peer-deps
-
This bypasses peer dependency checks and allows installation to proceed. The same approach may be required for other packages.
Recommendation:
- For long-term project health, align all package versions for compatibility, or consider replacing/upgrading/removing
react-day-pickerand/or downgrading React to 18.x if feasible. - Document any further workarounds and keep dependencies up to date as upstream packages add React 19 support.
-
Workflow Labeler File Ignored:
- The file
.github/workflows/labeler.ymlis intentionally listed in.gitignoreand will not be tracked or pushed to the repository. - This is done for local or experimental automation workflows that should not affect the main repository or CI/CD pipelines.
- If you need to use a labeler workflow, create your own local copy and ensure it is ignored in version control for best practices and clean code hygiene.
- The file
-
Components:
components/ChatbotButton.tsx,components/ChatbotWindow.tsx -
Logic:
lib/chatbot.ts,app/api/chatbot/route.ts(API integration and prompt) -
Config:
app/app-details-config.ts(centralized company name/branding) -
Tests:
tests/(see ai-integration.md for details)
Contributions are welcome! Please open an issue or submit a pull request for any improvements or bug fixes.
- Fork the repository
- Create your feature branch (
git checkout -b feature/YourFeature) - Commit your changes (
git commit -m 'Add some feature') - Push to the branch (
git push origin feature/YourFeature) - Open a pull request
This project is licensed under the MIT License.
For questions or support, please contact [email protected].
- Enhanced AI chatbot documentation for advanced usage, diagnostics, and extensibility.
- Improved error handling and user feedback for chatbot UI and backend integration.
- Documented OOP agent architecture and developer extension points.
- Added changelog for advanced diagnostics and agent-based discovery features.
- New Feature: Local AI fallback (
lib/my-ai-fallback.ts) is now used if OpenRouter is down or misconfigured. Developers can extend this fallback for their own models or scripts.
- Issue: YAML syntax error in
.github/workflows/codeql.ymldue to missingname:field in the step withif: matrix.build-mode == 'manual'. - Fix: Added a
name: Manual build instructionsto the affected step. This resolves the implicit map key error and ensures the workflow follows GitHub Actions and YAML best practices. - Reference: See
.github/workflows/codeql.yml, step under manual build instructions. - Reason: Every step must have a
name:when usingif:to avoid YAML parsing errors and improve workflow clarity. - YAML Best Practice: Comments above a step must not be indented as if they are part of the previous step. This ensures the YAML parser does not misinterpret comments as part of a previous mapping, which can cause 'implicit map key' errors. See the fix in
.github/workflows/codeql.ymlfor an example.
#
- Awaiting shipments now expose a random, unguessable
trackingCode(e.g.,SHIP-7G9X2A) for all user-facing tracking and display. - Internal IDs remain linear and are used only by backend/database logic.
- This change improves security, prevents tracking code enumeration, and keeps the UI professional and scalable.
- See
app/api/awaiting-shipments/route.tsandAwaitingShipmentTable.tsxfor implementation details and comments.
-
components/ChatbotButton.tsx
- Added a floating chat button available on all pages. Handles opening/closing the chatbot window.
-
components/ChatbotWindow.tsx
- Refactored outside click detection logic to use an OOP-based
OutsideClickHandlerclass. The chatbot window now receives achatButtonRefprop (aReact.RefObject<HTMLDivElement>) for robust outside click logic, improving maintainability and testability. This follows clean code, OOP, and dependency injection best practices. - Fixed a syntax error caused by a missing closing parenthesis in the component's return statement (see end of file). The return statement now ends with a closing parenthesis followed by the component's closing brace, ensuring valid JSX and TypeScript syntax. Added inline comments for clarity and to align with clean code architecture and best practices.
- Implements the main chatbot UI, message history, input, and displays bot/user avatars.
- Refactored outside click detection logic to use an OOP-based
-
lib/chatbot.ts
- Provides chatbot logic: time-based greetings, service intro, message history (localStorage, 10 messages), response caching, and API integration with OpenRouter.
- Handles error management and input sanitization.
-
app/layout.tsx
- Integrated so the chatbot is accessible site-wide.
-
app/app-details-config.ts
- Centralizes company name and branding for consistent chatbot responses.
-
app/api/chatbot/route.ts
- Handles server-side API requests to OpenRouter, including prompt construction and error handling.
-
public/avatar-nana.png, public/avatar-user.png
- Added professional avatars for bot and user.
-
.env.example
- Added required environment variables for OpenRouter API integration.
-
tests/
- Added unit tests for chatbot logic and UI components.
-
crosslogic.md
- Updated cross-app authentication logic: all secrets, URLs, and JWTs now use environment variables. See file for migration and deployment steps.
-
ai-integration.md
- Expanded documentation for chatbot setup, integration, and testing.
For more details on each change, see the respective file or the AI Chatbot Implementation and Cross-App Authentication sections above.