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:
25
packages/database/package.json
Normal file
25
packages/database/package.json
Normal 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"
|
||||
}
|
||||
}
|
||||
21
packages/shared/package.json
Normal file
21
packages/shared/package.json
Normal 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"
|
||||
}
|
||||
}
|
||||
18
packages/shared/src/index.ts
Normal file
18
packages/shared/src/index.ts
Normal 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;
|
||||
60
packages/shared/src/types/api.ts
Normal file
60
packages/shared/src/types/api.ts
Normal 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>;
|
||||
24
packages/shared/tsconfig.json
Normal file
24
packages/shared/tsconfig.json
Normal 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"
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user