feat(phase-0): setup Docker Compose with TypeScript monorepo structure

- Create monorepo structure with apps/ and packages/
- Add Docker Compose for api, web, db, redis, worker services
- Migrate existing Express.js logic to TypeScript with 100% backward compatibility
- Preserve all existing API endpoints (/api/track, /api/v1/track) with identical behavior
- Setup development environment with hot reload and proper networking
- Add comprehensive TypeScript configuration with path mapping
- Include production-ready Dockerfiles with multi-stage builds
- Maintain existing rate limiting (100 req/hour/IP) and response formats
- Add health checks and graceful shutdown handling
- Setup Turbo for efficient monorepo builds and development
This commit is contained in:
Andrei
2025-08-18 07:03:08 +00:00
parent fb63d91b7d
commit 956f1aeadb
28 changed files with 1748 additions and 14 deletions

View File

@@ -0,0 +1,18 @@
/**
* Shared utilities and types for Redirect Intelligence v2
*/
export * from './types/api';
export const constants = {
API_BASE_URL: process.env.REACT_APP_API_URL || 'http://localhost:3333',
RATE_LIMIT: {
WINDOW_MS: 60 * 60 * 1000, // 1 hour
MAX_REQUESTS: 100,
},
REDIRECT_LIMITS: {
MAX_HOPS: 20,
TIMEOUT_MS: 15000,
RESPONSE_BODY_LIMIT: 5000,
},
} as const;

View File

@@ -0,0 +1,60 @@
/**
* Shared API types for Redirect Intelligence v2
*/
import { z } from 'zod';
// Base API response
export const ApiResponseSchema = z.object({
success: z.boolean(),
status: z.number(),
data: z.any().optional(),
error: z.string().optional(),
message: z.string().optional(),
});
export type ApiResponse<T = any> = {
success: boolean;
status: number;
data?: T;
error?: string;
message?: string;
};
// Legacy redirect result (for backward compatibility)
export const LegacyRedirectSchema = z.object({
url: z.string(),
timestamp: z.number(),
isSSL: z.boolean(),
duration: z.number().optional(),
statusCode: z.number().optional(),
statusText: z.string().optional(),
metadata: z.any().optional(),
responseBody: z.string().optional(),
sslInfo: z.any().optional(),
error: z.string().optional(),
final: z.boolean().optional(),
});
export type LegacyRedirect = z.infer<typeof LegacyRedirectSchema>;
// Track request schemas
export const TrackRequestSchema = z.object({
url: z.string().url(),
method: z.enum(['GET', 'HEAD', 'POST']).default('GET'),
userAgent: z.string().optional(),
});
export type TrackRequest = z.infer<typeof TrackRequestSchema>;
// Track response schema
export const TrackResponseSchema = z.object({
url: z.string(),
method: z.string(),
redirectCount: z.number(),
finalUrl: z.string(),
finalStatusCode: z.number().optional(),
redirects: z.array(LegacyRedirectSchema),
});
export type TrackResponse = z.infer<typeof TrackResponseSchema>;