Oracle3
Oracle3: 예측시장 거래 엔진·MCP 서버
DocTrader Pro AI가 선택한 브로커에서 시스템 DocTrader Pro의 모든 거래를 계좌에 복제합니다
Doc Trader Pro AI replica en tu cuenta cada operación del sistema DocTrader Pro, en el broker que tú elijas. Tu dinero nunca sale de tu cuenta y el historial lo audita Myfxbook.
금융TypeScript · JavaScriptGitHub @DylanSrz온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기메이커가 쓴 소개는 위의 한 줄이 전부입니다. 더 자세한 내용은 저장소 README에서 읽을 수 있습니다. 저장소 README ↗
README 전체를 불러오는 중입니다.
README 전문 보기 ↗Plataforma web de licencias para Doc Trader Pro AI (doctraderpro.com).
| Carpeta | Qué es |
|---|---|
apps/web | Página pública y paneles (Next.js 16, Tailwind 4) |
apps/api | API y worker (NestJS 12, TypeORM, BullMQ). Mismo código, dos comandos de arranque |
packages/shared | Tipos y reglas de negocio puras (fechas de licencia, dinero, planes), con sus pruebas |
docker/ | Servicios de desarrollo: PostgreSQL, Redis, Mailpit y Adminer |
docs/, design/ | Planeación y prototipos |
Requisitos: Node 22 (ver .nvmrc), pnpm 10 (corepack enable) y Docker.
pnpm install
pnpm servicios # PostgreSQL, Redis, Mailpit (localhost:8025) y Adminer (localhost:8080)
cp apps/api/.env.example apps/api/.env # llena AUDIT_HMAC_KEY, DATA_ENCRYPTION_KEY, LOOKUP_HMAC_KEY y PROXY_SECRET
# (cada una: openssl rand -base64 32)
cp apps/web/.env.example apps/web/.env.local # PROXY_SECRET igual al de la API
pnpm db:migrar # crea las tablas
pnpm db:semilla # planes, ajustes, direcciones de depósito y los dos admins
pnpm dev # web en localhost:3000, API en localhost:4000
pnpm --filter @doctrader/api dev:worker # el worker, en otra terminal
localhost:4000/salud dice si la API ve la base de datos y Redis, y cuándo fue el último latido del worker.localhost:3000/sistema muestra el sistema de diseño (no existe en producción).localhost:8025. Sin Mailpit ni Resend,
el worker los escribe en su consola.| Comando | Qué hace |
|---|---|
pnpm lint · pnpm typecheck · pnpm format:check | Revisiones rápidas |
pnpm test | Pruebas unitarias de todos los paquetes |
pnpm --filter @doctrader/api test:e2e | Pruebas de la API contra Postgres y Redis reales, en la base doctrader_test (se borra y se recrea) |
pnpm build | Compila todo |
docs/MODELO-DATOS.md; funciones, módulos y textos en español.apps/api/src/database/migraciones/. Nunca synchronize.sumarMeses de
@doctrader/shared (hora de Colombia).AuditoriaService, dentro de la misma transacción que la acción.AvisosService.encolar) dentro de la transacción de la acción; el
worker los envía.llamarApi, firmada con PROXY_SECRET; la sesión vive en una cookie HttpOnly del dominio de la web.
Toda ruta de la API exige sesión salvo las marcadas @Publica(); los roles van con @Roles() y las acciones
delicadas con @ConfirmacionReciente().No hay Docker en producción. Las cuentas de Vercel y Railway están a nombre de Dylan (2026-10-14).
Add New → Project → importar DylanSrz/DocTrader.
Root Directory: apps/web. Vercel detecta Next.js y pnpm; el comando de build está en apps/web/vercel.json
(compila primero packages/shared).
Variables:
| Variable | Valor |
|---|---|
API_URL | El dominio de la API en Railway (después, https://api.doctraderpro.com) |
PROXY_SECRET | El mismo valor que en la API |
NEXT_PUBLIC_TURNSTILE_SITE_KEY | Clave pública de Cloudflare Turnstile (cuando exista la cuenta) |
MOSTRAR_SISTEMA | true solo en Preview, para ver /sistema |
SENTRY_DSN | Opcional: el DSN del proyecto de Sentry. Con él, los errores del servidor de la web llegan a Sentry, sin datos personales |
El dominio doctraderpro.com se conecta cuando la landing esté lista (etapa 2), no antes.
New Project → Deploy from GitHub repo → DylanSrz/DocTrader. Ese primer servicio es la API:
/salud,
con los valores de la tabla de "Lo que aprendimos" más abajo.api.doctraderpro.com).En el mismo proyecto: New → Database → PostgreSQL y New → Database → Redis.
New → GitHub repo otra vez, mismo repositorio: es el worker. Settings con los valores de la tabla de abajo. No necesita dominio.
Variables, en la API y en el worker (los mismos valores en los dos):
| Variable | Valor |
|---|---|
NODE_ENV | production |
DATABASE_URL | ${{Postgres.DATABASE_URL}} (red privada de Railway) |
DATABASE_SSL | false (la red privada no usa SSL) |
REDIS_URL | ${{Redis.REDIS_URL}} |
WEB_ORIGIN | La dirección de la web: https://www.doctraderpro.com (doctraderpro.com redirige ahí) |
AUDIT_HMAC_KEY | Una llave nueva: openssl rand -base64 32. Guárdala en el gestor de contraseñas: si se pierde, la auditoría vieja ya no se puede verificar |
DATA_ENCRYPTION_KEY | Otra llave nueva (openssl rand -base64 32). Cifra cédulas y segundos factores: si se pierde, esos datos no se recuperan |
LOOKUP_HMAC_KEY | Otra llave nueva (openssl rand -base64 32). Para buscar cédulas repetidas sin descifrarlas |
DATA_ENCRYPTION_KEY_VERSION, DATA_ENCRYPTION_KEY_ANTERIOR, AUDIT_HMAC_KEY_ANTERIOR | Solo al rotar llaves: ver docs/ROTACION-CREDENCIALES.md |
RESEND_API_KEY | La llave de Resend (cuando el dominio esté verificado). Sin ella, los correos esperan en cola |
GitHub Actions (.github/workflows/) corre formato, lint, tipos, pruebas unitarias, pruebas de punta a punta,
build, búsqueda de secretos (gitleaks) y CodeQL en cada pull request. Dependabot propone actualizaciones cada semana.
Railway: el plan Hobby no permite programar copias del volumen. Con el plan Pro se pueden activar en Postgres → Backups (y la recuperación a un momento dado); es opcional, porque la copia diaria de abajo ya cubre esto.
Copia diaria fuera de Railway (.github/workflows/copia-de-seguridad.yml): todos los días a las 3:17 a. m. de
Colombia copia la base de datos, la restaura en un Postgres vacío y la revisa, la cifra (AES-256 con una frase) y
la guarda en un depósito privado de R2, 30 días. Se puede correr a mano desde Actions → "Copia de seguridad" → Run
workflow. Necesita estos secretos del repositorio (Settings → Secrets and variables → Actions); sin ellos avisa y no
hace nada:
| Secreto | Valor |
|---|---|
BACKUP_DATABASE_URL | La URL pública de Postgres en Railway (DATABASE_PUBLIC_URL), copiada ya resuelta (sin ${{…}}) |
BACKUP_PASSPHRASE | Una frase larga (openssl rand -base64 32). Guárdala en el gestor de contraseñas: sin ella las copias no se abren |
BACKUP_R2_ACCOUNT_ID, BACKUP_R2_ACCESS_KEY_ID, BACKUP_R2_SECRET_ACCESS_KEY, BACKUP_R2_BUCKET | Un depósito de R2 privado solo para copias (doctrader-copias) y un token de R2 con lectura y escritura solo en él |
Restaurar una copia (en una base de datos nueva, nunca encima de producción sin pensarlo dos veces):
doctrader-AAAA-MM-DD.dump.gpg desde el depósito de R2.gpg --decrypt doctrader-AAAA-MM-DD.dump.gpg > doctrader.dump (pide la frase).pg_restore --no-owner --no-privileges -d <url-de-la-base-nueva> doctrader.dump.DATABASE_URL de la API y el worker a la base restaurada solo después de revisarla.Los clientes de hoy son de prueba. Antes de abrir se corre apps/api/dist/database/limpiar.js dentro de Railway: la
base de datos de producción no es alcanzable desde fuera de su red privada (salvo el proxy TCP). Sin railway ssh, se
hace con el paso previo al despliegue de la API (Settings → Deploy → Pre-deploy Command):
node apps/api/dist/database/preparar-despliegue.js && node apps/api/dist/database/limpiar.js y se redespliega la API. Los registros del despliegue muestran lo que se
borraría, sin cambiar nada.CONFIRMAR_LIMPIEZA=borrar-todos-los-clientes en la API (redespliega sola). Borra todos
los clientes con sus cuentas, licencias, órdenes, tickets, adjuntos, correos y referidos (comisiones, pagos y
perfiles), y reinicia los números de orden (DTP-000001) y de ticket (1000). Quedan los admins, el socio con su
perfil de referidos, los ajustes, los planes, las direcciones de depósito, los textos legales, las preguntas y las
respuestas guardadas. La auditoría no se toca (no admite borrados). Los registros dicen cuántos admins quedan.CONFIRMAR_LIMPIEZA vacía y el paso previo de nuevo en
node apps/api/dist/database/preparar-despliegue.js. Aunque la variable quedara puesta, no se vuelve a borrar: la
limpieza deja la marca launch_cleanup_at en settings y, con ella, se niega.files), vaciar el depósito doctrader-adjuntos en Cloudflare R2: eran de prueba.| Pieza | Dirección |
|---|---|
Web (Vercel, proyecto doc_trader_pro) | https://doctraderpro-khaki.vercel.app |
API (Railway, proyecto happy-adventure) | https://doctraderapi-production.up.railway.app (/salud) |
| Worker (Railway) | Sin dominio; su latido se ve en /salud de la API |
Lo que aprendimos al configurar Railway:
Railway ya no aplica los archivos railway.json ("Config as Code" quedó obsoleto; ahora es .railway/railway.ts).
Los de apps/api/railway/ quedan solo como referencia: la configuración real se pone en Settings de cada
servicio (2026-10-15):
API (@doctrader/api) | Worker | |
|---|---|---|
| Build Command | pnpm install --frozen-lockfile && pnpm --filter @doctrader/api build | igual |
| Start Command | node apps/api/dist/main.js | node apps/api/dist/worker.js |
| Pre-deploy Command | node apps/api/dist/database/preparar-despliegue.js (migraciones y semilla) | — |
| Healthcheck Path | /salud | — |
| Restart Policy | On failure | Always |
| Watch Paths | apps/api/**, packages/shared/**, pnpm-lock.yaml | igual |
Sin el pre-deploy, la base de datos queda vacía y la API responde 500 ("relation users does not exist"). Sin el build command, Railway compila todo el monorepo (incluida la web) y la compilación puede tardar 12 minutos y caerse.
"Redeploy" de un despliegue viejo usa la configuración de ese momento: después de cambiar Settings hay que hacer un despliegue nuevo del último commit.
Al importar el repositorio, Railway crea un servicio por paquete del monorepo. Solo se dejan la API y el worker.
Root Directory vacío en los dos servicios.
La ruta del archivo de configuración lleva barra inicial (/apps/api/railway/api.json); los comandos no
(node apps/api/dist/worker.js): el código vive en la carpeta de trabajo del contenedor, no en la raíz.
R2_ACCOUNT_ID, R2_ACCESS_KEY_ID, R2_SECRET_ACCESS_KEY, R2_BUCKET | Cloudflare R2 privado para los adjuntos de soporte (token de R2 con lectura y escritura solo en ese depósito). Sin ellas, los tickets funcionan sin adjuntos |
SENTRY_DSN | Opcional: el DSN del proyecto de Sentry (el mismo de la web). Sin ella, los errores solo quedan en los registros de Railway |
Solo en la API, además:
| Variable | Valor |
|---|---|
PROXY_SECRET | Otra llave nueva (openssl rand -base64 32), la misma de Vercel. Sin ella la API no arranca en producción |
TURNSTILE_SECRET | Clave secreta de Cloudflare Turnstile (cuando exista la cuenta) |
COINGECKO_API_KEY | Opcional: llave gratis de CoinGecko (plan Demo) para comparar el precio de BTC con más consultas |
TRONGRID_API_KEY, TRONSCAN_API_KEY | Opcionales, también en el worker: llaves gratis de TronGrid y Tronscan para verificar pagos en Tron con más consultas |
BINANCE_API_KEY, BINANCE_API_SECRET | Opcionales, en el worker: llave de solo lectura de la cuenta de Binance de cobro, para verificar los pagos entre cuentas de Binance (sin hash). Sin ellas, esos pagos se revisan a mano. El worker debe correr fuera de Estados Unidos |
Revisar https://<dominio-de-la-api>/salud: debe responder "estado":"ok" y, al minuto, mostrar el latido del
worker. Sin el secreto de la web, cualquier otra ruta responde 404, salvo /archivos/subir: la subida de
adjuntos que hace el navegador directo, con una ficha firmada de 30 minutos (por eso WEB_ORIGIN debe ser la
dirección exacta de la web: es el origen que la API acepta).