devx: easier way to run the server + debugger
This commit is contained in:
parent
40b98cdc17
commit
9cf6b979da
@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"permissions": {
|
|
||||||
"allow": [
|
|
||||||
"Bash(yarn add:*)",
|
|
||||||
"Bash(yarn build)"
|
|
||||||
],
|
|
||||||
"deny": []
|
|
||||||
}
|
|
||||||
}
|
|
78
.cursorrules
78
.cursorrules
@ -1,78 +0,0 @@
|
|||||||
You are an expert in Typescript and Node.js. You are building a web server in opponiated framework.
|
|
||||||
|
|
||||||
Tool usage
|
|
||||||
- When in doubt - use web tool to get answers from the web.
|
|
||||||
- Search web when you have some failures.
|
|
||||||
|
|
||||||
Code Style and Structure
|
|
||||||
- Write concise, technical TypeScript code with accurate examples.
|
|
||||||
- Use functional and declarative programming patterns; avoid classes.
|
|
||||||
- Prefer iteration and modularization over code duplication.
|
|
||||||
- Use descriptive variable names with auxiliary verbs (e.g., isLoading, hasError).
|
|
||||||
- All sources must be imported using "@/" prefix. `import "@/utils/log"` means `import "/sources/utils/log.ts"`.
|
|
||||||
- Always use absolute imports.
|
|
||||||
|
|
||||||
Folder structure
|
|
||||||
- Root of the sources is "/sources"
|
|
||||||
- Non-application logic files are in "/sources/modules"
|
|
||||||
- Low level or too abstract utilities are in "/sources/utils"
|
|
||||||
- Recipes, ie scripts that you want to run outside of the server are in "/sources/recipes"
|
|
||||||
- Applications are in /sources/apps
|
|
||||||
- API server is in /sources/apps/api with routes in /sources/apps/api/routes
|
|
||||||
- Modules are in /sources/modules
|
|
||||||
|
|
||||||
Naming Conventions
|
|
||||||
- Use lowercase with dashes for directories (e.g., components/auth-wizard).
|
|
||||||
|
|
||||||
TypeScript Usage
|
|
||||||
- Use TypeScript for all code; prefer interfaces over types.
|
|
||||||
- Avoid enums; use maps instead.
|
|
||||||
- Use functional components with TypeScript interfaces.
|
|
||||||
- Use strict mode in TypeScript for better type safety.
|
|
||||||
|
|
||||||
Tests
|
|
||||||
- Write tests using Vitest.
|
|
||||||
- Always name test files in the same way as the source file, but with ".spec.ts" suffix.
|
|
||||||
|
|
||||||
Utilities
|
|
||||||
- When writing utility function always name file and function in the same way, so it is easy to find it.
|
|
||||||
- Utility functions should be modular and not too complex.
|
|
||||||
- When writing utility functions, always write tests for them BEFORE writing the code.
|
|
||||||
- Iterate your implementation and tests until you are sure that the function works as expected.
|
|
||||||
- When writing utility functions, always write documentation for them.
|
|
||||||
|
|
||||||
Modules
|
|
||||||
- Modules are bigger than utility functions and their goal is to abstract away complexity
|
|
||||||
- Each module should have dedicated directory.
|
|
||||||
- Modules usually don't have application specific logic, they are more general and could be copied to other projects.
|
|
||||||
- Modules can depend on other modules, but should not depend on application specific logic.
|
|
||||||
- Prefer to write code as modules instead of application specific code.
|
|
||||||
- When using a module is a good idea:
|
|
||||||
- When you need to integrate with external services
|
|
||||||
- When you need to abstract away complexity of some library
|
|
||||||
- When you want to implement some group of functions that are related to each other, like math, date, etc.
|
|
||||||
- Some known modules are:
|
|
||||||
- ai: AI wrappers to interact with AI services
|
|
||||||
- eventbus: event bus to send and receive events between modules and applications
|
|
||||||
- lock: simple lock to synchronize access to resources in the whole cluster
|
|
||||||
- media: tools to work with media files
|
|
||||||
|
|
||||||
Applications
|
|
||||||
- Applications has some application specific logic
|
|
||||||
- Applications have the most of the complexity and other parts of the code should assist by reducing complexity here.
|
|
||||||
- When using prompts, write them to "_prompts.ts" file relative to the application.
|
|
||||||
|
|
||||||
Database
|
|
||||||
- Prisma is used as ORM.
|
|
||||||
- Use "inTx" to wrap database operations in transactions.
|
|
||||||
- Do not update schema without absolute necessity.
|
|
||||||
- For complex fields, use "Json" type.
|
|
||||||
|
|
||||||
Events
|
|
||||||
- eventbus allows to send and receive events inside of the process and between different processes.
|
|
||||||
- eventbus is local or redis based.
|
|
||||||
- use "afterTx" to send events after transaction is committed successfully instead of directly emitting events.
|
|
||||||
|
|
||||||
Libraries
|
|
||||||
- Always use Zod for validation of inputs.
|
|
||||||
- Always use axios for HTTP requests.
|
|
1
.cursorrules
Symbolic link
1
.cursorrules
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
CLAUDE.md
|
@ -1,4 +1,3 @@
|
|||||||
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/handy
|
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/handy
|
||||||
REDIS_URL=redis://localhost:6379
|
HANDY_MASTER_SECRET=your-super-secret-key-for-local-development
|
||||||
SEED=your-seed-for-token-generation
|
PORT=3005
|
||||||
PORT=3005
|
|
||||||
|
6
.gitignore
vendored
6
.gitignore
vendored
@ -4,4 +4,8 @@ dist
|
|||||||
.pgdata
|
.pgdata
|
||||||
|
|
||||||
.env.local
|
.env.local
|
||||||
.env
|
.env
|
||||||
|
|
||||||
|
.logs/
|
||||||
|
|
||||||
|
.claude/
|
||||||
|
30
.vscode/launch.json
vendored
Normal file
30
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"type": "node",
|
||||||
|
"request": "launch",
|
||||||
|
"name": "Debug Server",
|
||||||
|
"runtimeExecutable": "npx",
|
||||||
|
"runtimeArgs": [
|
||||||
|
"tsx",
|
||||||
|
"--inspect",
|
||||||
|
"./sources/main.ts"
|
||||||
|
],
|
||||||
|
"env": {
|
||||||
|
"NODE_ENV": "development"
|
||||||
|
},
|
||||||
|
"envFile": "${workspaceFolder}/.env.local",
|
||||||
|
"cwd": "${workspaceFolder}",
|
||||||
|
"console": "integratedTerminal",
|
||||||
|
"internalConsoleOptions": "neverOpen",
|
||||||
|
"skipFiles": [
|
||||||
|
"<node_internals>/**"
|
||||||
|
],
|
||||||
|
"resolveSourceMapLocations": [
|
||||||
|
"${workspaceFolder}/**",
|
||||||
|
"!**/node_modules/**"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -8,12 +8,12 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsc --noEmit",
|
"build": "tsc --noEmit",
|
||||||
"start": "tsx ./sources/main.ts",
|
"start": "tsx ./sources/main.ts",
|
||||||
"dev": "lsof -ti tcp:3005 | xargs kill -9 && tsx --env-file=.env.local ./sources/main.ts",
|
"dev": "tsx --env-file=.env.local ./sources/main.ts",
|
||||||
"test": "vitest",
|
"test": "vitest",
|
||||||
"migrate": "prisma migrate dev",
|
"migrate": "dotenv -e .env.local -- prisma migrate dev",
|
||||||
"generate": "prisma generate",
|
"generate": "prisma generate",
|
||||||
"postinstall": "prisma generate",
|
"postinstall": "prisma generate",
|
||||||
"db": "docker run -e POSTGRES_PASSWORD=postgres -v $(pwd)/.pgdata:/var/lib/postgresql/data -p 5432:5432 postgres"
|
"db": "docker run -e POSTGRES_PASSWORD=postgres -e POSTGRES_DB=handy -v $(pwd)/.pgdata:/var/lib/postgresql/data -p 5432:5432 postgres"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/chalk": "^2.2.0",
|
"@types/chalk": "^2.2.0",
|
||||||
@ -21,6 +21,7 @@
|
|||||||
"@types/node": "^20.12.3",
|
"@types/node": "^20.12.3",
|
||||||
"@types/tmp": "^0.2.6",
|
"@types/tmp": "^0.2.6",
|
||||||
"@types/uuid": "^9.0.8",
|
"@types/uuid": "^9.0.8",
|
||||||
|
"dotenv-cli": "^8.0.0",
|
||||||
"ts-node": "^10.9.2",
|
"ts-node": "^10.9.2",
|
||||||
"typescript": "^5.4.3",
|
"typescript": "^5.4.3",
|
||||||
"yaml": "^2.4.2"
|
"yaml": "^2.4.2"
|
||||||
@ -40,6 +41,7 @@
|
|||||||
"fastify-type-provider-zod": "^4.0.2",
|
"fastify-type-provider-zod": "^4.0.2",
|
||||||
"ioredis": "^5.4.1",
|
"ioredis": "^5.4.1",
|
||||||
"jsonwebtoken": "^9.0.2",
|
"jsonwebtoken": "^9.0.2",
|
||||||
|
"pino-pretty": "^13.0.0",
|
||||||
"prisma": "^6.11.1",
|
"prisma": "^6.11.1",
|
||||||
"prisma-json-types-generator": "^3.5.1",
|
"prisma-json-types-generator": "^3.5.1",
|
||||||
"privacy-kit": "^0.0.23",
|
"privacy-kit": "^0.0.23",
|
||||||
|
@ -1,7 +1,46 @@
|
|||||||
import pino from 'pino';
|
import pino from 'pino';
|
||||||
|
import { mkdirSync } from 'fs';
|
||||||
|
import { join } from 'path';
|
||||||
|
|
||||||
|
const isDebug = process.env.DEBUG === 'true' || process.env.NODE_ENV === 'development';
|
||||||
|
const logsDir = join(process.cwd(), '.logs');
|
||||||
|
|
||||||
|
if (isDebug) {
|
||||||
|
try {
|
||||||
|
mkdirSync(logsDir, { recursive: true });
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to create logs directory:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const transports: any[] = [];
|
||||||
|
|
||||||
|
transports.push({
|
||||||
|
target: 'pino-pretty',
|
||||||
|
options: {
|
||||||
|
colorize: true,
|
||||||
|
translateTime: 'HH:MM:ss.l',
|
||||||
|
ignore: 'pid,hostname',
|
||||||
|
messageFormat: '{levelLabel} [{time}] {msg}',
|
||||||
|
errorLikeObjectKeys: ['err', 'error'],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (isDebug) {
|
||||||
|
transports.push({
|
||||||
|
target: 'pino/file',
|
||||||
|
options: {
|
||||||
|
destination: join(logsDir, `server-${new Date().toISOString().split('T')[0]}.log`),
|
||||||
|
mkdir: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export const logger = pino({
|
export const logger = pino({
|
||||||
level: 'info',
|
level: isDebug ? 'debug' : 'info',
|
||||||
|
transport: {
|
||||||
|
targets: transports,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export function log(src: any, ...args: any[]) {
|
export function log(src: any, ...args: any[]) {
|
||||||
@ -10,4 +49,12 @@ export function log(src: any, ...args: any[]) {
|
|||||||
|
|
||||||
export function warn(src: any, ...args: any[]) {
|
export function warn(src: any, ...args: any[]) {
|
||||||
logger.warn(src, ...args);
|
logger.warn(src, ...args);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function error(src: any, ...args: any[]) {
|
||||||
|
logger.error(src, ...args);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function debug(src: any, ...args: any[]) {
|
||||||
|
logger.debug(src, ...args);
|
||||||
}
|
}
|
29
yarn.lock
29
yarn.lock
@ -1140,6 +1140,15 @@ cross-spawn@^7.0.3:
|
|||||||
shebang-command "^2.0.0"
|
shebang-command "^2.0.0"
|
||||||
which "^2.0.1"
|
which "^2.0.1"
|
||||||
|
|
||||||
|
cross-spawn@^7.0.6:
|
||||||
|
version "7.0.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f"
|
||||||
|
integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==
|
||||||
|
dependencies:
|
||||||
|
path-key "^3.1.0"
|
||||||
|
shebang-command "^2.0.0"
|
||||||
|
which "^2.0.1"
|
||||||
|
|
||||||
date-fns@^4.1.0:
|
date-fns@^4.1.0:
|
||||||
version "4.1.0"
|
version "4.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-4.1.0.tgz#64b3d83fff5aa80438f5b1a633c2e83b8a1c2d14"
|
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-4.1.0.tgz#64b3d83fff5aa80438f5b1a633c2e83b8a1c2d14"
|
||||||
@ -1196,6 +1205,26 @@ diff@^4.0.1:
|
|||||||
resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d"
|
resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d"
|
||||||
integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==
|
integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==
|
||||||
|
|
||||||
|
dotenv-cli@^8.0.0:
|
||||||
|
version "8.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/dotenv-cli/-/dotenv-cli-8.0.0.tgz#cea1519f5a06c7372a1428fca4605fcf3d50e1cf"
|
||||||
|
integrity sha512-aLqYbK7xKOiTMIRf1lDPbI+Y+Ip/wo5k3eyp6ePysVaSqbyxjyK3dK35BTxG+rmd7djf5q2UPs4noPNH+cj0Qw==
|
||||||
|
dependencies:
|
||||||
|
cross-spawn "^7.0.6"
|
||||||
|
dotenv "^16.3.0"
|
||||||
|
dotenv-expand "^10.0.0"
|
||||||
|
minimist "^1.2.6"
|
||||||
|
|
||||||
|
dotenv-expand@^10.0.0:
|
||||||
|
version "10.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/dotenv-expand/-/dotenv-expand-10.0.0.tgz#12605d00fb0af6d0a592e6558585784032e4ef37"
|
||||||
|
integrity sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A==
|
||||||
|
|
||||||
|
dotenv@^16.3.0:
|
||||||
|
version "16.6.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.6.1.tgz#773f0e69527a8315c7285d5ee73c4459d20a8020"
|
||||||
|
integrity sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==
|
||||||
|
|
||||||
dotenv@^16.4.5:
|
dotenv@^16.4.5:
|
||||||
version "16.4.5"
|
version "16.4.5"
|
||||||
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.5.tgz#cdd3b3b604cb327e286b4762e13502f717cb099f"
|
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.5.tgz#cdd3b3b604cb327e286b4762e13502f717cb099f"
|
||||||
|
Loading…
Reference in New Issue
Block a user