Skip to content

refactor: add comprehensive coding standards and tooling - #1

Open
MylesMCook wants to merge 4 commits into
mainfrom
claude/refine-codebase-zHkEo
Open

MylesMCook wants to merge 4 commits into
mainfrom
claude/refine-codebase-zHkEo

Conversation

@MylesMCook

Copy link
Copy Markdown
Owner
  • Add ESLint with strict TypeScript and React rules
  • Add Prettier for consistent code formatting
  • Set up Vitest testing framework with 40 tests for date-parser
  • Enable ESLint and TypeScript checking during builds
  • Clean up package.json (rename to tempus-total, remove unused deps)
  • Add comprehensive CONTRIBUTING.md with coding guidelines
  • Update README with complete documentation
  • Update aiRules.md to reflect current project structure
  • Add .env.example for environment configuration
  • Clean up date-parser.ts (remove console.log, fix unused vars)
  • Add .gitignore and .prettierignore files

- Add ESLint with strict TypeScript and React rules
- Add Prettier for consistent code formatting
- Set up Vitest testing framework with 40 tests for date-parser
- Enable ESLint and TypeScript checking during builds
- Clean up package.json (rename to tempus-total, remove unused deps)
- Add comprehensive CONTRIBUTING.md with coding guidelines
- Update README with complete documentation
- Update aiRules.md to reflect current project structure
- Add .env.example for environment configuration
- Clean up date-parser.ts (remove console.log, fix unused vars)
- Add .gitignore and .prettierignore files
Copilot AI review requested due to automatic review settings January 8, 2026 00:47
@vercel

vercel Bot commented Jan 8, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
v0-tempus-total-v2 Error Error Jan 8, 2026 1:43am

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements comprehensive coding standards and development tooling for the TempusTotal project. The changes establish a professional development workflow with linting, formatting, testing, and thorough documentation.

Key Changes:

  • Added ESLint, Prettier, and Vitest for code quality and testing
  • Enabled strict TypeScript and ESLint checking during builds
  • Cleaned up package.json (renamed project, removed unused dependencies, organized deps)
  • Added comprehensive documentation (CONTRIBUTING.md with 666 lines of guidelines)
  • Created 40 unit tests for the date-parser with proper test setup
  • Cleaned up date-parser.ts (removed console.log, fixed unused variables)

Reviewed changes

Copilot reviewed 13 out of 15 changed files in this pull request and generated 12 comments.

Show a summary per file
File Description
vitest.config.mts Configures Vitest testing framework with coverage thresholds (70%/60%) and jsdom environment
package.json Renames to tempus-total, adds test/lint/format scripts, reorganizes dependencies, updates versions
next.config.mjs Enables ESLint and TypeScript checking during builds, adds performance optimizations
eslint.config.mjs Comprehensive ESLint configuration with TypeScript, React, accessibility, and import rules
app/lib/date-parser.ts Removes console.log statements, fixes unused variables, improves error handling with proper typing
aiRules.md Updates project structure documentation and development guidelines to reflect current state
tests/setup.ts Test environment setup with mocks for DOM APIs, localStorage, and clipboard
tests/date-parser.test.ts 40 comprehensive tests covering date parsing edge cases and functionality
README.md Complete rewrite with API documentation, examples, tech stack, and configuration details
CONTRIBUTING.md Extensive 666-line guide covering architecture, code style, TypeScript, React, API, testing, and git workflow
.prettierrc Prettier configuration with Tailwind CSS plugin support
.prettierignore Prettier ignore patterns for build outputs and dependencies
.gitignore Updated ignore patterns with better organization
.env.example Environment variable template for analytics and API configuration

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread eslint.config.mjs Outdated
Comment on lines +191 to +192
Blob: "readonly",
File: "readonly",

Copilot AI Jan 8, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The 'Blob' and 'File' globals are duplicated - they appear both at lines 58-59 and again at lines 191-192. Remove the duplicate declarations to avoid confusion.

Suggested change
Blob: "readonly",
File: "readonly",

Copilot uses AI. Check for mistakes.
Comment thread eslint.config.mjs Outdated
DeviceOrientationEvent: "readonly",
Gamepad: "readonly",
GamepadEvent: "readonly",
PointerEvent: "readonly",

Copilot AI Jan 8, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The 'PointerEvent' global is duplicated - it appears at line 73 and again at line 230. Remove one of the duplicate declarations.

Suggested change
PointerEvent: "readonly",

Copilot uses AI. Check for mistakes.
Comment thread .prettierrc
"htmlWhitespaceSensitivity": "css",
"embeddedLanguageFormatting": "auto",
"plugins": ["prettier-plugin-tailwindcss"],
"tailwindConfig": "./tailwind.config.js",

Copilot AI Jan 8, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Prettier configuration references './tailwind.config.js' but the actual Tailwind config file might be named 'tailwind.config.ts' or 'tailwind.config.mjs' (common in Next.js projects). Verify that the file path matches the actual Tailwind configuration file name in the project, otherwise the Tailwind CSS class sorting plugin will not work correctly.

Copilot uses AI. Check for mistakes.
Comment thread package.json
"lru-cache": "latest",
"date-fns-tz": "latest",
"nanoid": "latest"
"zod": "^3.24.1"

Copilot AI Jan 8, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Several dependencies have been removed that were listed with 'latest' version (@remix-run/react, @sveltejs/kit, svelte, vue, vue-router, crypto). While cleaning up unused dependencies is good, verify that none of these packages were actually being used in the codebase. The 'crypto' package in particular might have been used for utilities, though Node.js provides a built-in crypto module.

Copilot uses AI. Check for mistakes.
Comment thread package.json
"@vitejs/plugin-react": "^4.3.4",
"@vitest/coverage-v8": "^2.1.8",
"@vitest/ui": "^2.1.8",
"autoprefixer": "^10.4.20",

Copilot AI Jan 8, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The autoprefixer dependency has been moved from dependencies to devDependencies. However, autoprefixer is typically needed during the build process by PostCSS/Tailwind CSS. While it may work in this setup (since Next.js handles the build), verify that production builds still work correctly after this change, especially if the app is deployed in environments where devDependencies are not installed.

Copilot uses AI. Check for mistakes.
Comment thread eslint.config.mjs
Comment on lines +40 to +243
globals: {
React: "readonly",
JSX: "readonly",
NodeJS: "readonly",
console: "readonly",
process: "readonly",
Buffer: "readonly",
setTimeout: "readonly",
clearTimeout: "readonly",
setInterval: "readonly",
clearInterval: "readonly",
fetch: "readonly",
URL: "readonly",
URLSearchParams: "readonly",
Request: "readonly",
Response: "readonly",
Headers: "readonly",
FormData: "readonly",
Blob: "readonly",
File: "readonly",
AbortController: "readonly",
AbortSignal: "readonly",
Event: "readonly",
EventTarget: "readonly",
CustomEvent: "readonly",
MessageEvent: "readonly",
ErrorEvent: "readonly",
ProgressEvent: "readonly",
ClipboardEvent: "readonly",
DragEvent: "readonly",
FocusEvent: "readonly",
KeyboardEvent: "readonly",
MouseEvent: "readonly",
PointerEvent: "readonly",
TouchEvent: "readonly",
WheelEvent: "readonly",
AnimationEvent: "readonly",
TransitionEvent: "readonly",
UIEvent: "readonly",
InputEvent: "readonly",
CompositionEvent: "readonly",
document: "readonly",
window: "readonly",
navigator: "readonly",
localStorage: "readonly",
sessionStorage: "readonly",
location: "readonly",
history: "readonly",
performance: "readonly",
requestAnimationFrame: "readonly",
cancelAnimationFrame: "readonly",
requestIdleCallback: "readonly",
cancelIdleCallback: "readonly",
IntersectionObserver: "readonly",
MutationObserver: "readonly",
ResizeObserver: "readonly",
PerformanceObserver: "readonly",
MediaQueryList: "readonly",
matchMedia: "readonly",
getComputedStyle: "readonly",
HTMLElement: "readonly",
HTMLInputElement: "readonly",
HTMLButtonElement: "readonly",
HTMLDivElement: "readonly",
HTMLSpanElement: "readonly",
HTMLAnchorElement: "readonly",
HTMLFormElement: "readonly",
HTMLImageElement: "readonly",
HTMLVideoElement: "readonly",
HTMLAudioElement: "readonly",
HTMLCanvasElement: "readonly",
HTMLTextAreaElement: "readonly",
HTMLSelectElement: "readonly",
HTMLOptionElement: "readonly",
HTMLTableElement: "readonly",
HTMLTableRowElement: "readonly",
HTMLTableCellElement: "readonly",
Element: "readonly",
Node: "readonly",
NodeList: "readonly",
DocumentFragment: "readonly",
Text: "readonly",
Comment: "readonly",
DOMParser: "readonly",
XMLSerializer: "readonly",
SVGElement: "readonly",
Map: "readonly",
Set: "readonly",
WeakMap: "readonly",
WeakSet: "readonly",
Promise: "readonly",
Proxy: "readonly",
Reflect: "readonly",
Symbol: "readonly",
BigInt: "readonly",
ArrayBuffer: "readonly",
SharedArrayBuffer: "readonly",
DataView: "readonly",
Int8Array: "readonly",
Uint8Array: "readonly",
Uint8ClampedArray: "readonly",
Int16Array: "readonly",
Uint16Array: "readonly",
Int32Array: "readonly",
Uint32Array: "readonly",
Float32Array: "readonly",
Float64Array: "readonly",
BigInt64Array: "readonly",
BigUint64Array: "readonly",
JSON: "readonly",
Math: "readonly",
Date: "readonly",
Intl: "readonly",
Error: "readonly",
TypeError: "readonly",
RangeError: "readonly",
SyntaxError: "readonly",
ReferenceError: "readonly",
EvalError: "readonly",
URIError: "readonly",
AggregateError: "readonly",
Object: "readonly",
Array: "readonly",
String: "readonly",
Number: "readonly",
Boolean: "readonly",
Function: "readonly",
RegExp: "readonly",
encodeURIComponent: "readonly",
decodeURIComponent: "readonly",
encodeURI: "readonly",
decodeURI: "readonly",
atob: "readonly",
btoa: "readonly",
structuredClone: "readonly",
queueMicrotask: "readonly",
reportError: "readonly",
isNaN: "readonly",
isFinite: "readonly",
parseFloat: "readonly",
parseInt: "readonly",
globalThis: "readonly",
crypto: "readonly",
Crypto: "readonly",
CryptoKey: "readonly",
SubtleCrypto: "readonly",
TextEncoder: "readonly",
TextDecoder: "readonly",
ReadableStream: "readonly",
WritableStream: "readonly",
TransformStream: "readonly",
Blob: "readonly",
File: "readonly",
FileReader: "readonly",
FileList: "readonly",
Image: "readonly",
Audio: "readonly",
Video: "readonly",
WebSocket: "readonly",
Worker: "readonly",
SharedWorker: "readonly",
ServiceWorker: "readonly",
BroadcastChannel: "readonly",
MessageChannel: "readonly",
MessagePort: "readonly",
Notification: "readonly",
indexedDB: "readonly",
IDBDatabase: "readonly",
IDBObjectStore: "readonly",
IDBIndex: "readonly",
IDBCursor: "readonly",
IDBTransaction: "readonly",
IDBRequest: "readonly",
IDBKeyRange: "readonly",
caches: "readonly",
Cache: "readonly",
CacheStorage: "readonly",
Storage: "readonly",
StorageEvent: "readonly",
CloseEvent: "readonly",
BeforeUnloadEvent: "readonly",
PageTransitionEvent: "readonly",
PopStateEvent: "readonly",
HashChangeEvent: "readonly",
SecurityPolicyViolationEvent: "readonly",
PromiseRejectionEvent: "readonly",
DeviceMotionEvent: "readonly",
DeviceOrientationEvent: "readonly",
Gamepad: "readonly",
GamepadEvent: "readonly",
PointerEvent: "readonly",
SpeechRecognition: "readonly",
SpeechSynthesis: "readonly",
ScreenOrientation: "readonly",
Screen: "readonly",
Geolocation: "readonly",
GeolocationPosition: "readonly",
GeolocationCoordinates: "readonly",
GeolocationPositionError: "readonly",
Clipboard: "readonly",
ClipboardItem: "readonly",
Permissions: "readonly",
PermissionStatus: "readonly",
},

Copilot AI Jan 8, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The globals configuration is extremely verbose with 243 individual global declarations. This approach is error-prone and difficult to maintain. Consider using a standard globals preset from the 'globals' npm package (e.g., globals.browser, globals.node, globals.es2021) which provides these common globals automatically and is less verbose.

Copilot uses AI. Check for mistakes.
Comment thread eslint.config.mjs Outdated
Comment on lines +257 to +262
"import/resolver": {
typescript: {
alwaysTryTypes: true,
project: "./tsconfig.json",
},
},

Copilot AI Jan 8, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The import/resolver configuration references 'typescript' but the required 'eslint-import-resolver-typescript' package is not listed in the devDependencies. This will cause the import plugin to fail when trying to resolve TypeScript imports. Add 'eslint-import-resolver-typescript' to devDependencies.

Copilot uses AI. Check for mistakes.
Comment thread eslint.config.mjs Outdated
Response: "readonly",
Headers: "readonly",
FormData: "readonly",
Blob: "readonly",

Copilot AI Jan 8, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This property is duplicated in a later property.

Suggested change
Blob: "readonly",

Copilot uses AI. Check for mistakes.
Comment thread eslint.config.mjs Outdated
Headers: "readonly",
FormData: "readonly",
Blob: "readonly",
File: "readonly",

Copilot AI Jan 8, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This property is duplicated in a later property.

Suggested change
File: "readonly",

Copilot uses AI. Check for mistakes.
Comment thread eslint.config.mjs Outdated
FocusEvent: "readonly",
KeyboardEvent: "readonly",
MouseEvent: "readonly",
PointerEvent: "readonly",

Copilot AI Jan 8, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This property is duplicated in a later property.

Suggested change
PointerEvent: "readonly",

Copilot uses AI. Check for mistakes.
- Fix rate-limit.ts for Next.js 15 async headers() API
- Fix date-parser.ts type inference for Token[] and direction type
- Fix date-picker.tsx Date arithmetic operations
- Fix api/parse/route.ts async rate limiting and proper typing
- Fix analytics.ts and security-monitor.ts type issues
- Fix self-closing component warnings in layout.tsx, loading.tsx
- Clean up unused imports and variables in page.tsx
- Simplify ESLint config to avoid import resolver issues
- Update use-toast.ts type declarations

All 40 tests pass, TypeScript compiles without errors.
Replace Geist/Inter Google Fonts with system font stack to avoid
build failures when Google Fonts API is unreachable. The app now
uses the default system UI fonts which load instantly and work
offline.

- Remove next/font/google imports from layout.tsx
- Update tailwind.config.js to use system font stack
- Build now completes successfully

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 23 out of 26 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread lib/security-monitor.ts
duration: 0,
success: false,
expression: "SECURITY_ALERT",
expression: `SECURITY_ALERT:${clientIp}`,

Copilot AI Jan 8, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The metrics.addMetric call is passing additional fields (clientIp, eventType) that are not defined in the APIMetrics interface. According to the monitoring.ts interface, APIMetrics only accepts: timestamp, duration, success, expression, and statusCode. The clientIp is now being embedded in the expression field as a workaround, but the eventType field is being removed entirely. This could cause issues if the monitoring system expects this data for security events.

Suggested change
expression: `SECURITY_ALERT:${clientIp}`,
expression: `SECURITY_ALERT:suspicious-activity:${clientIp}`,

Copilot uses AI. Check for mistakes.
Comment thread CONTRIBUTING.md
Comment on lines +488 to +489
it("should throw ParseError when expression exceeds max length", () => {
expect(() => parseExpression("a".repeat(201))).toThrow(ParseError);

Copilot AI Jan 8, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The example shows testing a ParseError being thrown, but the actual date-parser.ts implementation returns null for invalid input rather than throwing errors. This inconsistency between the documentation example and the actual implementation could confuse contributors.

Suggested change
it("should throw ParseError when expression exceeds max length", () => {
expect(() => parseExpression("a".repeat(201))).toThrow(ParseError);
it("should return null when expression exceeds max length", () => {
expect(parseExpression("a".repeat(201))).toBeNull();

Copilot uses AI. Check for mistakes.
Comment thread app/api/parse/route.ts
// This ensures the API works smoothly during development and for UI components
if (!isSameOrigin) {
try {
// More generous limit per IP - 200 requests per minute for external users

Copilot AI Jan 8, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The rate limiter check is set to 60 requests per minute, but the comment says "200 requests per minute for external users". This mismatch between the comment and the actual limit value could lead to confusion. Update the comment to match the actual limit of 60 requests per minute.

Suggested change
// More generous limit per IP - 200 requests per minute for external users
// Rate limit per IP - 60 requests per minute for external users

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants