Instruction file imported from lofitrades/trading-clock (
.github/instructions/t2t_Instructions.instructions.md). Copyright stays with the author.
Time 2 Trade (T2T) - GitHub Copilot Instructions
Version: 4.3.0
Last Updated: February 2, 2026
Purpose: AI agent guidelines for working with Time 2 Trade codebase
🚨 CRITICAL: Read This First
Before Making ANY Changes:
-
📖 READ THE KNOWLEDGE BASE
- Open
kb/kb.mdand read relevant sections - Contains: architecture, tech stack, data models, patterns, troubleshooting
- DO NOT duplicate kb.md content - reference it instead
- Open
-
🔍 UNDERSTAND CONTEXT
- Use semantic search to find related code
- Check component dependencies and imports
- Review existing patterns before implementing new ones
-
📝 FILE HEADERS ARE MANDATORY Every file MUST start with:
/** * relative/path/to/file.ext * * Purpose: Brief description (2-3 lines max) * Key responsibility and main functionality * * Changelog: * v1.1.0 - 2026-01-16 - Added feature X * v1.0.0 - 2025-09-15 - Initial implementation */ -
🔄 UPDATE DOCUMENTATION
- After significant changes, update
kb/kb.md→ Change Log - Update version numbers in affected file headers
- Keep descriptions concise and actionable
- After significant changes, update
🎯 Project Context
What: Trading session clock with dual-circle design (AM inner, PM outer) for futures/forex traders
URL: https://time2.trade/
Key Features:
- 8 customizable trading sessions with visual clock arcs
- Economic events calendar (multi-source: NFS, JBlanked/MQL5, GPT fallback)
- Timezone support with automatic conversions
- Cloud sync settings via Firebase
- PWA installable app
- SEO-optimized multi-page SPA
Tech: React 19 + Vite 6 + MUI v7 + Firebase (Auth, Firestore, Functions v2)
For details: See kb/kb.md → Project Overview, Tech Stack, Architecture
🗺️ Routing Architecture
Route Structure
| Route | Component | Access | Purpose |
|---|---|---|---|
/ |
LandingPage |
Public | SEO-optimized marketing page |
/clock |
ClockPage |
Public | Primary app - Market clock UI |
/app |
HomePage |
Public | Legacy app shell (noindex) |
/calendar |
CalendarPage |
Public | Economic events calendar |
/about |
AboutPage |
Public | About page |
/privacy |
PrivacyPage |
Public | Privacy policy |
/terms |
TermsPage |
Public | Terms of service |
/contact |
ContactPage |
Public | Contact form |
/login |
LoginPage |
Public (restricted) | Standalone passwordless auth (fallback) |
/upload-desc |
UploadDescriptions |
Admin | Upload event descriptions |
/export |
ExportEvents |
Admin | Export events to JSON |
/fft2t |
FFTTUploader |
Superadmin | GPT event uploader |
Authentication UI
- Primary:
AuthModal2.jsx- Used throughout app (landing, calendar, settings) - Fallback:
/loginroute - For direct links and magic link callbacks
Route Guards
PublicRoute- Accessible to all, optionalrestrictedprop redirects authenticated usersPrivateRoute- Requires authentication, supportsrolesandplansprops
Key Files
src/routes/AppRoutes.jsx- Route configurationsrc/components/routes/PublicRoute.jsx- Public route guardsrc/components/routes/PrivateRoute.jsx- Private route guard
📁 Critical File Rules
🚫 NEVER MODIFY:
src/firebase.js- Firebase configuration (already set up).env/functions/.env- Environment variables (NEVER commit)src/components/ClockCanvas.jsx- Native Canvas API (DO NOT replace with MUI)
✅ PRIMARY COMPONENTS (Actively Used):
src/components/AuthModal2.jsx- Primary auth UI (800+ lines, fully MUI)src/components/SettingsSidebar2.jsx- Primary settings drawer (1330+ lines, fully MUI)src/components/CalendarEmbed.jsx- Calendar workspace componentsrc/components/EventsFilters3.jsx- Event filtering UIsrc/components/EventsTimeline2.jsx- Timeline viewsrc/components/EventsTable.jsx- Table view
⚠️ LEGACY COMPONENTS (Being Phased Out):
src/components/AuthModal.jsx- Legacy auth (use AuthModal2)src/components/SettingsSidebar.jsx- Legacy settings (use SettingsSidebar2)
📖 KEY REFERENCE FILES:
kb/kb.md- Primary documentation (read first!)src/hooks/useClock.js- Session detection logicsrc/hooks/useSettings.js- Settings persistencesrc/hooks/useCalendarData.js- Calendar data fetchingsrc/services/economicEventsService.js- Events servicesrc/services/canonicalEconomicEventsService.js- Canonical eventssrc/utils/clockUtils.js- Canvas drawing utilities
🏗️ Architecture Quick Reference
State Management
AuthContext- User authentication state + role managementSettingsContext- User settings (clock, sessions, preferences)- Custom hooks for feature-specific state
Data Flow
- User visits → Load route → Check auth state
- Auth modal (AuthModal2) → Magic link or Google OAuth
- Clock updates → Detect active session → Update UI
- Settings change → Debounced Firestore sync
- Guest mode → localStorage fallback
Firebase Collections
users/ # User profiles + settings
economicEvents/ # Canonical events (multi-source)
└─ events/ # Event documents
└─ {eventDocId}
├─ canonicalName
├─ currency
├─ date
├─ sources: { nfs, jblanked, gpt }
└─ ...
economicEventsCalendar/ # Legacy per-source events
economicEventDescriptions/ # Event descriptions + trading tips
systemJobs/ # Background job tracking
Cloud Functions (functions/src/)
| Function | Purpose |
|---|---|
syncEconomicEventsCalendarScheduled |
Daily 5 AM EST sync |
syncEconomicEventsCalendarNow |
Manual sync trigger |
nfsSyncService.ts |
NFS week sync |
jblankedActualsService.ts |
JBlanked actuals sync |
gptUploadService.ts |
GPT placeholder ingest |
For architecture details: See kb/kb.md → Architecture Overview
🧩 Component Architecture
Page Layouts
AppRoutes
├── PublicLayout (marketing pages)
│ ├── AppBar / NavigationMenu
│ ├── CookiesBanner
│ └── Page Content
├── AppLayout (app pages)
│ ├── AppBar (sticky)
│ ├── Main Content
│ └── Mobile Bottom Nav
└── Modals (global)
├── AuthModal2 (z-index: 12001)
├── WelcomeModal (z-index: 11000)
├── ContactModal
└── ConfirmModal
Clock Components
ClockPage / HomePage
├── ClockCanvas.jsx (Canvas API - ASK TO MODIFY PROVIDING A REASON FOR THE UPDATE)
├── ClockEventsOverlay.jsx (event markers)
├── ClockHandsOverlay.jsx (hand overlays)
├── DigitalClock.jsx
├── SessionLabel.jsx
└── TimezoneSelector.jsx
Calendar Components
CalendarPage
└── CalendarEmbed.jsx
├── EventsFilters3.jsx
├── NewsSourceSelector.jsx
├── EventsTable.jsx / EventsTimeline2.jsx
├── EventModal.jsx
└── EventNotesDialog.jsx
Z-Index Stack (IMPORTANT)
12001-12004 AuthModal2 + nested modals (HIGHEST)
11000 WelcomeModal
10000 EmailLinkHandler verification
2000 High-priority modals
1600 SettingsSidebar2 drawer
1400 AppBar / Bottom navigation
1200 Popovers, tooltips
1100 Sticky headers
🪝 Hooks Reference
| Hook | Purpose |
|---|---|
useClock.js |
Clock tick, session detection, time calculations |
useSettings.js |
Settings persistence (Firestore + localStorage) |
useCalendarData.js |
Calendar data fetching with filters |
useClockEventMarkers.js |
Clock overlay marker calculations |
useClockEventsData.js |
Clock events data fetching |
useEventNotes.js |
User event notes CRUD |
useFavorites.js |
Event favorites management |
useFullscreen.js |
Fullscreen mode toggle |
useTimeEngine.js |
Advanced time calculations |
🔧 Services Reference
| Service | Purpose |
|---|---|
economicEventsService.js |
Main events API (fetch, sync, filter) |
canonicalEconomicEventsService.js |
Canonical multi-source events |
eventNotesService.js |
User notes Firestore operations |
favoritesService.js |
Favorites Firestore operations |
eventsCache.js |
LocalStorage caching layer |
firestoreHelpers.js |
Firestore utility functions |
📝 Coding Standards
React Best Practices
// ✅ DO: Functional components with hooks
const Component = ({ prop }) => {
const [state, setState] = useState(init);
useEffect(() => { /* cleanup */ return () => {}; }, [deps]);
return <div>...</div>;
};
// ✅ DO: Memoize expensive operations
const value = useMemo(() => compute(a, b), [a, b]);
const MemoComponent = React.memo(({ data }) => <div>{data}</div>);
// ✅ DO: Use lazy loading for routes/modals
const AuthModal2 = lazy(() => import('./AuthModal2'));
// ❌ DON'T: Class components, inline complex logic, missing dependency arrays
MUI Components
// ✅ DO: Use sx prop with theme values
<Button variant="contained" color="primary" sx={{ mt: 2, px: 3 }}>
Click Me
</Button>
// ✅ DO: Use slotProps for Dialog customization
<Dialog
sx={{ zIndex: 12001 }}
slotProps={{
backdrop: { sx: { zIndex: -1 } },
paper: { sx: { borderRadius: 3 } },
}}
>
// ❌ DON'T: Inline styles, styled-components, className for dynamic styles
Firebase Patterns
// ✅ DO: Proper cleanup and serverTimestamp
useEffect(() => {
const unsub = onAuthStateChanged(auth, (user) => setUser(user));
return () => unsub();
}, []);
await setDoc(doc(db, 'users', uid), {
createdAt: serverTimestamp(),
});
// ❌ DON'T: Client timestamps, missing unsubscribe, no error handling
File Naming
- Components: PascalCase (
AuthModal2.jsx) - Hooks: camelCase with
useprefix (useClock.js) - Services: camelCase with Service suffix (
economicEventsService.js) - Utils: camelCase (
clockUtils.js) - TypeScript:
.tsxfor components,.tsfor logic
🌍 Internationalization (i18n) Standards
CRITICAL: Zero Hardcoded Client-Facing Copy
NO hardcoded user-visible text in components. All client-facing strings MUST use i18n translation keys.
ENTERPRISE BEP STANDARD:
- ✅ Namespace preload strategy controlled globally in
src/i18n/config.js(ONLY) - ✅ Components use
useTranslation('namespace')without worrying about loading - ✅ No translation keys ever visible to users (add namespace to preload list if needed)
- ✅ All namespace decisions made at app startup, not during render
- ❌ NO lazy-loading logic within individual components
- ❌ NO dynamic namespace imports or loadNamespace() calls
Architecture (v2.0.0 - HTTP Backend Lazy Loading)
Performance-First Design:
- ✅ Lazy loading via
i18next-http-backend- Load only active language + namespace - ✅ Zero static imports - Translations served as static assets from
public/locales/ - ✅ 180 kB bundle reduction (-24%) - Main bundle: 751 kB → 571 kB
- ✅ Browser caching - Independent cache invalidation from JS bundle
- ✅ Preload strategy - Critical namespaces (common, pages) loaded immediately
File Structure:
src/i18n/locales/ ← SOURCE OF TRUTH (edit here)
├─ en/ (30 namespaces)
├─ es/ (30 namespaces)
└─ fr/ (30 namespaces)
public/locales/ ← AUTO-GENERATED (served via HTTP)
├─ en/ (30 namespaces)
├─ es/ (30 namespaces)
└─ fr/ (30 namespaces)
src/i18n/
└─ config.js ← HTTP backend config (zero imports)
scripts/
└─ sync-locales.mjs ← Syncs src → public before build
Key Files:
src/i18n/config.js- HTTP backend configurationsrc/components/LanguageSwitcher.jsx- Language switching with preloadsrc/contexts/LanguageContext.jsx- Language state + Firestore syncscripts/sync-locales.mjs- Locale sync script (prebuild hook)
See: I18N_PERFORMANCE_OPTIMIZATION.md for detailed implementation guide
Implementation Pattern
// ✅ DO: Use useTranslation hook with namespace
import { useTranslation } from 'react-i18next';
const Component = () => {
// Namespace MUST be in i18n/config.js ns array (global config only)
// Don't worry about whether it loads - config handles that
const { t } = useTranslation('calendar');
return (
<div>
<h1>{t('title')}</h1>
<Button>{t('actions.save')}</Button>
</div>
);
};
// ✅ DO: Use useMemo for translated strings with dependencies
const translatedValue = useMemo(() => t('key'), [t]);
// ❌ DON'T: Hardcode strings
<h1>Welcome to Time 2 Trade</h1>
// ❌ DON'T: Try to lazy-load namespaces within components
useEffect(() => {
i18n.loadNamespace('events'); // WRONG - use i18n/config.js instead
}, []);
// ❌ DON'T: Import JSON files directly (breaks lazy loading)
import enCommon from './locales/en/common.json'; // WRONG
Locale Structure
- Location (Source):
src/i18n/locales/[en|es|fr]/[namespace].json(for reference) - Location (Served):
public/locales/[en|es|fr]/[namespace].json(HTTP backend) - Namespaces (26):
common,pages,auth,settings,calendar,events,dialogs,filter,reminders,about,legal,terms,privacy, etc. - Supported Languages: EN (English), ES (Español), FR (Français)
🔑 Golden Rule: Only Edit src/i18n/locales/
Everything else is automatic. The build process handles syncing to public/locales/.
src/i18n/locales/ (EDIT HERE - source of truth, Git tracked)
│
▼ npm run build → prebuild syncs automatically
│
public/locales/ (AUTO-GENERATED - don't edit directly)
│
▼ Vite builds + prerender generates SEO
│
dist/ (Runtime + SEO use same translations)
Workflow:
| Task | Command |
|---|---|
| Edit translations | Edit src/i18n/locales/[lang]/[file].json |
| Test locally | npm run sync-locales then refresh |
| Deploy | npm run deploy (sync is automatic) |
| Check for orphans | npm run sync-locales (warns if any) |
| Clean orphans | npm run sync-locales -- --clean |
Adding Translations (BEP Process)
- Identify all client-facing copy in the component (buttons, labels, headings, descriptions, etc.)
- Create translation keys with descriptive namespaced paths:
namespace.section.key - Add to all 3 language files in
src/i18n/locales/:src/i18n/locales/en/[namespace].jsonsrc/i18n/locales/es/[namespace].jsonsrc/i18n/locales/fr/[namespace].json
- Run
npm run sync-localesto copy topublic/locales/(or let build do it) - Use consistent terminology across all locales:
- "Market Clock" (EN) → "Reloj de Mercado" (ES) → "Horloge du Marché" (FR)
- Brand terms capitalized in titles, lowercase in descriptions where appropriate
- Verify all 3 languages are complete before marking task complete
Namespace Loading Strategy
Global Control (i18n/config.js ONLY):
- All preload/lazy-load decisions are made in
src/i18n/config.jsvia thensarray - Components should NOT attempt to lazy-load namespaces themselves
- Every namespace used by any component should be explicitly listed in config
Current Preload List (Immediate):
common- Navigation, footer, shared UI (~3 kB gzipped)pages- Landing page, marketing (~6 kB gzipped)filter- Event filters on /calendar page (~2 kB gzipped)
How It Works:
// In i18n/config.js - this controls EVERYTHING
ns: ['common', 'pages', 'filter'], // All these load immediately on app start
// In components - just use the namespace, don't worry about loading
const { t } = useTranslation('filter'); // Already available (preloaded)
// OR
const { t } = useTranslation('events'); // Would fail if 'events' not in ns array
Adding a New Namespace:
- Check which pages/routes use the namespace
- If used on public routes (/calendar, /, /about, etc.) → Add to
ns:preload list - If used only in modals/private routes → Document in comments, but still add to avoid flashing keys
- Update
src/i18n/config.js- that's the ONLY place for loading strategy - Components just use
useTranslation('namespace')- no special handling needed
Common Namespaces
| Namespace | Usage | Example Keys |
|---|---|---|
pages |
Marketing & public pages (landing, about, FAQ) | pages:landing.hero.heading |
auth |
Authentication UI (modals, forms) | auth:headline, auth:verifyEmail |
settings |
Settings & preferences | settings:clockSettings.heading |
dialogs |
Modal & dialog content | dialogs:cookies.heading |
common |
Shared/navigation terms | common:navigation.clock |
calendar |
Calendar workspace | calendar:header.title |
events |
Event-related UI | events:showOnClock |
Translation Key Format
{
"namespace": {
"section": {
"key": "Display text here"
}
}
}
Parameter Support
// Translations can include dynamic values
const copyright = useMemo(
() => t('pages:footer.copyright', { year: new Date().getFullYear() }),
[t]
);
// In locale file:
// "copyright": "© {{year}} Time 2 Trade. All rights reserved."
🚨 Critical Constraints
DO NOT:
- ❌ Modify Firebase config or commit credentials
- ❌ Replace ClockCanvas.jsx with MUI (uses native Canvas API)
- ❌ Break auth flow (magic links + OAuth must work)
- ❌ Change session detection without testing midnight crossover
- ❌ Add external CSS frameworks (Bootstrap, Tailwind)
- ❌ Use
document.getElementById(use refs) - ❌ Add console.logs in production (only if temporarily requested for debugging)
- ❌ Change Firestore structure without migration plan
- ❌ Lower AuthModal2 z-index below 12001
- ❌ Modify canonical events structure without updating all sources
- ❌ Build and deploy when unnecessary, only if required to see the updates in localhost and prod. Do not 'npm run build' or 'firebase deploy' before requesting approval.
- ❌ Run 'npm run dev' before checking if a server is already running on localhost:5173 to avoid port conflicts and open simple browser instead (if required).
- ❌ Hardcode any client-facing copy - All user-visible strings MUST use i18n with t() keys and full translations in en/es/fr locale files
ALWAYS:
- ✅ Test auth flows (magic link, Google OAuth, logout)
- ✅ Verify settings persist (Firestore + localStorage fallback)
- ✅ Check responsive design (mobile, tablet, desktop)
- ✅ Ensure at least 1 clock element is visible (toggle constraint)
- ✅ Test timezone changes update clock correctly
- ✅ Verify Canvas hover tooltips work
- ✅ Test route guards (public vs private routes)
- ✅ Verify z-index layering on mobile
- ✅ Replace ALL client-facing copy with i18n keys - Add translations to all 3 languages (EN/ES/FR) in appropriate namespaces before task complete
Performance
- Clock updates: 1 second interval (not 60fps)
- Canvas:
requestAnimationFrame, cache static elements - Settings: Debounced Firestore updates (500ms)
- Routes: Lazy loading with Suspense
- Events: LocalStorage caching with 24-hour expiry
🧪 Testing Priorities
Authentication
- Magic link email flow (send → click → verify)
- Google OAuth (new user + returning user)
- Logout and session cleanup
- Role-based access (admin, superadmin)
Routing
- Public routes accessible without auth
- Private routes redirect to /login
- Restricted routes redirect authenticated users
- 404 handling
Settings Persistence
- Firestore save/load when logged in
- localStorage fallback for guests
- Default settings for new users
Calendar & Events
- Multi-source event fetching (NFS, JBlanked, GPT)
- Filter persistence across sessions
- Event notes CRUD
- Favorites sync
Responsive Design
- Desktop (1200px+), Tablet (768-1199px), Mobile (<768px)
- Safe area handling (notch, home indicator)
For complete checklist: See kb/kb.md → Testing Strategy
🔧 Development Workflow
Local Development
npm install # Install dependencies
npm run dev # Start dev server (http://localhost:5173)
npm run build # Build for production (includes prerender)
npm run lint # Lint code
npm run preview # Preview production build
Cloud Functions
cd functions
npm install # Install function dependencies
npm run build # Build TypeScript
firebase deploy --only functions # Deploy functions
Deployment (Firebase Hosting - Primary)
npm run deploy # Build + deploy to Firebase Hosting
Production URL: https://time2.trade/
Git Workflow
- Main branch:
main(protected) - Feature branches:
feature/description - Bug fixes:
bugfix/description - DO NOT commit:
.env,functions/.env,node_modules/,dist/
🐛 Common Issues
| Issue | Solution |
|---|---|
| Blank screen on load | Check body bg-color is F9F9F9, verify route exists, check console |
| Settings not persisting | Verify user authenticated, check Firestore rules, inspect network |
| Session not detecting | Verify 24-hour format, correct timezone, test midnight crossover |
| Canvas not scaling | Check devicePixelRatio, verify ctx.scale(dpr, dpr) |
| Auth modal behind AppBar | Ensure z-index is 12001+, check slotProps backdrop |
| Magic link fails | Check authorized domains in Firebase Console, verify SMTP config |
| Events not loading | Check canonical collection path, verify sync job ran |
| Route not found | Check AppRoutes.jsx, ensure component is lazy loaded |
For detailed troubleshooting: See kb/kb.md → Troubleshooting Guide
📚 Quick Reference Links
Primary Documentation:
kb/kb.md- Comprehensive knowledge base (READ FIRST)kb/BrandGuide.md- Brand colors, typography, logo usagekb/TargetAudience.md- User personas and JTBD
External APIs:
- JBlanked API: https://jblanked.com/api/docs/news-calendar-api
Framework Docs:
- MUI: https://mui.com/material-ui/getting-started/
- Firebase: https://firebase.google.com/docs
- React Router: https://reactrouter.com/en/main
📈 Current Priorities
✅ Completed (v3.0.0 → v4.2.0)
- Multi-page SPA routing architecture
- i18n lazy loading optimization (180 kB bundle reduction)
- AuthModal2 - Full MUI auth with magic links
- SettingsSidebar2 - Full MUI settings drawer
- Canonical economic events (multi-source)
- Calendar page with embed component
- PWA support with install prompt
- SEO optimization with prerender
- Firebase Analytics integration
- Event notes and favorites
- Clock events overlay
📋 Technical Debt
- Remove legacy AuthModal.jsx and SettingsSidebar.jsx
- Add unit tests (Vitest) and E2E tests (Playwright)
- Implement error boundaries
- Add file headers to remaining files
For full roadmap: See kb/kb.md → Change Log
💡 Key Principles
- Simplicity First: Minimal design, no unnecessary decorations
- Reference, Don't Duplicate: Point to kb.md instead of repeating details
- User Experience: Dynamic backgrounds, text color adaptation, responsive design
- Performance: Memoization, debouncing, Canvas caching, lazy loading
- Accessibility: Clear error messages, informative tooltips, keyboard navigation
- Consistency: Follow existing patterns, maintain file header format, update docs
- Mobile-First: Design for mobile, enhance for desktop
- Auth-Gated Gracefully: Show value before requiring login, use AuthModal2
Last Updated: February 2, 2026
Version: 4.3.0 (Multi-page SPA + Full i18n Standards + BEP Internationalization + Locale Sync)
Need more details? → Read kb/kb.md for comprehensive documentation on architecture, tech stack, data models, security rules, deployment procedures, and troubleshooting guides.
Additonal instructions or clarifications can be appended here as needed:
- 'bep'/'BEP' = 'following all best React, Firebase, MUI, UI, UX, dev, copywriting, security, performance, loading speed (lazy loading), separation of concerns, SEO, accessibility, i18n-and-theme-aware, and mobile-first-responsive top modern enterprise practices'.
- i18n Standard: All client-facing copy MUST use translation keys (t keys) with full translations in EN/ES/FR locale files before deployment.