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,25 @@
{
"name": "@redirect-intelligence/database",
"version": "2.0.0",
"private": true,
"scripts": {
"db:generate": "prisma generate",
"db:migrate": "prisma migrate dev",
"db:deploy": "prisma migrate deploy",
"db:studio": "prisma studio",
"db:seed": "tsx prisma/seed.ts",
"db:reset": "prisma migrate reset"
},
"dependencies": {
"@prisma/client": "^5.7.1"
},
"devDependencies": {
"prisma": "^5.7.1",
"tsx": "^4.6.2",
"@types/node": "^20.10.0",
"typescript": "^5.3.0"
},
"prisma": {
"seed": "tsx prisma/seed.ts"
}
}

View File

@@ -0,0 +1,21 @@
{
"name": "@redirect-intelligence/shared",
"version": "2.0.0",
"private": true,
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"build": "tsc",
"dev": "tsc --watch",
"clean": "rm -rf dist",
"lint": "eslint src --ext .ts",
"lint:fix": "eslint src --ext .ts --fix"
},
"dependencies": {
"zod": "^3.22.4"
},
"devDependencies": {
"typescript": "^5.3.0",
"@types/node": "^20.10.0"
}
}

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>;

View File

@@ -0,0 +1,24 @@
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"lib": ["ES2020"],
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"declaration": true,
"declarationMap": true,
"sourceMap": true
},
"include": [
"src/**/*"
],
"exclude": [
"node_modules",
"dist"
]
}