Ctrl K
ComunidadGuías…

CLAUDE.md

Rama master · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Trunk

The trunk branch is **`master`** (GitHub default branch for `AlessioBrillo/dominus`).
The `github-workflow` skill aligns to this. A future rename to `main` is
a deliberate, separate change.

## Project

DOMINUS is an open-source domain investment decision-support tool, available as
a self-hosted community edition (AGPL v3) and a managed cloud service
(DOMINUS Cloud). The community edition is single-user by default, zero-cost on
APIs, and runs at €0 infrastructure cost. DOMINUS Cloud adds multi-tenancy,
managed PostgreSQL, team accounts, and priority support.

The core asset is the **scoring engine**: a heuristic valuator that outputs
`expected_value`, `confidence`, `suggested_buy_max`, and `suggested_list_price`
per domain candidate. The engine must be more conservative than commercial
appraisal tools, not more generous.

See [ADR-0001](docs/adr/0001-project-architecture.md) for original architecture
decisions (superseded by ADR-0026, ADR-0027 for the SaaS era).

## Current stack

| Layer              | Technology                                                     |
| ------------------ | -------------------------------------------------------------- |
| **Backend**        | Node.js 22+, Express 5                                         |
| **Database**       | SQLite (community) / PostgreSQL (cloud)                        |
| **CLI**            | Commander (23 commands)                                        |
| **API**            | Express REST (34 route modules)                                |
| **Frontend**       | React 19 + Vite 8 + Tailwind CSS 4 + Recharts + TanStack Table |
| **Trademark**      | USPTO public API (no key) + EUIPO OAuth2                       |
| **Infrastructure** | Docker, Docker Compose, Terraform (Hetzner), GitHub Actions    |

See [ADR-0001](docs/adr/0001-project-architecture.md) for the original rationale
behind the technology choices. ADR-0025 through ADR-0028 document the SaaS
transition.

## Pipeline architecture

Five-stage pipeline with async-first execution — acquisition and auto-listing
are manual and out of scope:

1. **Candidate generation** — keyword combos, brandable names, closeout CSVs imported manually
2. **DNS pre-filter** — fast bulk check via Unbound recursive resolver
   (DNSSEC-validated; Node.js DNS fallback for non-Available verdicts only;
   never reports Available without DNSSEC validation)
3. **RDAP confirmation** — precise availability status + premium detection via public RDAP
4. **Scoring** — heuristic engine (see below)
5. **Trademark gate** — mandatory USPTO/EUIPO check; any match blocks the candidate

Pipeline runs are **async by default**: the CLI and API enqueue jobs to the
`job_queue` table and return immediately. The in-process `JobWorker` polls for
pending jobs and executes handlers asynchronously (configurable via
`WORKER_ENABLED`, default `true`). Callers can use `--sync` on the CLI,
`dominus runs wait <runId>` for polling, or the `/api/v1/runs/:id/job`
endpoint for API status. The `PipelineRunService` exposes both `runSync()`
and `enqueueRun()` paths; the legacy synchronous path is maintained for
backward compatibility.

Plus a **portfolio tracker**: renewal clock per domain, monthly keep/drop verdict.

All five stages are implemented and running. See [ADR-0003](docs/adr/0003-pipeline-stage-separation.md) for the architectural design.

## Scoring engine signals

- **Intrinsic**: length, pronounceability, hyphens/numbers (penalty), TLD
- **Commercial**: keyword search volume × CPC from Google Keyword Planner
- **Market**: comparables from NameBio sales for similar names
- **For expired/closeout domains**: domain age, backlinks, Wayback history.
  Wayback is fetched automatically (CDX provider); age and backlinks come from
  the imported closeout CSV — there is no backlink provider.

Weights are tuned manually against real comparable sales. ML is out of scope
at this scale — heuristic only. See [ADR-0002](docs/adr/0002-scoring-engine-design.md)
for the conservatism principle and [ADR-0008](docs/adr/0008-backtest-engine.md)
for the backtest-driven tuning loop.

## Key design decisions

- **Decision-first UX**: one question per candidate — _buy / pass_. One question
  per portfolio domain — _keep / drop / reprice_.
- **Trademark gate is non-negotiable** — it runs on every candidate before any
  buy recommendation. See [ADR-0006](docs/adr/0006-trademark-gate-mandate.md).
- **Provider abstraction is non-negotiable** — never hardcode a specific API
  client into core logic. See [ADR-0004](docs/adr/0004-provider-abstraction-pattern.md).
- **Cost discipline**: no paid API is required for the community edition.
  Every feature runs at €0 infra cost.
  See [ADR-0001](docs/adr/0001-project-architecture.md).
- **Community-first**: the AGPL community edition has every feature that
  DOMINUS Cloud has. Monetisation is on managed infrastructure, not feature gating.
  See [ADR-0025](docs/adr/0025-license-change-agpl-commercial.md).
- **Renewal clock matters more than acquisition volume**: a domain that doesn't
  sell is a recurring liability. Drop logic is a first-class feature.
- **Zero lock-in**: migrate from DOMINUS Cloud to self-hosted with a single
  database dump. The community edition reads the same schema.

## Production operations

- **Backup**: Automatic daily backup via scheduler (`SCHEDULER_BACKUP_CRON`, default: 04:00).
  Manual backup: `dominus maintenance backup`. See [ADR-0022](docs/adr/0022-backup-and-operations.md).
- **Database maintenance**: `dominus maintenance vacuum` runs integrity check + VACUUM.
- **Pruning**: `dominus maintenance prune` removes expired cache/runs data.
- **Local CI**: Pre-push hook runs full quality gate (typecheck, build, lint, format, test)
  before every push. No GitHub Actions minutes required.

## Project status

DOMINUS v1.5.2 — the artifact tells the truth: `dominus doctor` reports its own version,
database state, backup age and disk space on any installation, fresh or existing.
`npm run launch:check` judges a community deployment and a Cloud deployment
with the same implementation (profiles, auto-detection, `--paid`), writes
JSON and Markdown evidence on pass and on fail, and checks the things that
break silently in public: the canonical origin, TLS, HSTS/CSP, HTML/JSON
parity, robots → sitemap and the live trademark canary (ADR-0100).
`npm run launch:rehearse` builds the production-parity Cloud stack, runs the
gate against it and writes the evidence, with no credentials and no spend.
The community edition is the first soft launch; the Cloud stays behind the
fiscal position, the third-party audit ([audit-scope.md](docs/security/audit-scope.md))
and a real staging deployment ([first-apply.md](docs/deployment/first-apply.md)).
Before it: the verified install channel, the legal surface, the
data-subject rights and a release state checked against the world. v1.0.0
introduced the DOMINUS Cloud MVP.
Next: execute the first staging apply, the audit, and the fiscal position.
See the [ADR series](docs/adr/README.md) for the full architecture documentation,
and [ROADMAP.md](ROADMAP.md) for planned releases.

Resolved design decisions:

1. **Starting segment: economic closeouts first** — Stage 1 imports closeout
   CSVs (`run --closeout-csv`), carrying age/backlinks/wayback into the
   expiry signal. See [ADR-0003](docs/adr/0003-pipeline-stage-separation.md).
2. **Interface: CLI + Dashboard** — the React dashboard is the primary UI for
   DOMINUS Cloud; the CLI remains fully functional for automation.
   See [ADR-0028](docs/adr/0028-frontend-architecture-professional-dashboard.md).
3. **Registrar**: manual purchases by default. The [RegistrarProvider]
   interface has one verified production implementation, Cloudflare;
   Dynadot, Porkbun and Namecheap providers are registered but marked
   experimental (unverified against vendor APIs — see ADR-0082). Use
   `REGISTRAR_PROVIDER=manual` (default) unless you have verified
   credentials.
   See [ADR-0004](docs/adr/0004-provider-abstraction-pattern.md).
4. **Drop policy** — defaults live in config (`DROP_SCORE_THRESHOLD`,
   `DROP_RENEWAL_HORIZON_DAYS`); thresholds are tuned via backtest feedback.
5. **Async-default execution** — pipeline runs enqueue to job_queue by default;
   call `--sync` for immediate synchronous execution. The worker is enabled
   by default (`WORKER_ENABLED=true`). See [ADR-0023](docs/adr/0023-job-queue-worker-pool-architecture.md).
6. **License**: AGPL v3 + commercial option. Community edition is free forever.
   See [ADR-0025](docs/adr/0025-license-change-agpl-commercial.md).
7. **SaaS model**: hosting-only monetisation — no feature gating.
   See [ADR-0026](docs/adr/0026-monetization-and-saas-model.md).
8. **Database abstraction**: SQLite for community, PostgreSQL for cloud.
   See [ADR-0027](docs/adr/0027-saas-architecture-multi-tenant.md).

Providers default to free/manual data: `KeywordProvider` reads an optional
local file (`KEYWORD_DATA_PATH`) or uses Google Suggest; `CompsProvider` reads
an optional local file (`COMPS_DATA_PATH`). Google Ads (keywords) and NameBio
(comparables) are optional API implementations. Adding a provider means one new
implementation file — no core logic changes. Providers that cannot be verified
against the real service are not shipped (see
[ADR-0082](docs/adr/0082-removal-of-unimplemented-features.md)).
See [ADR-0004](docs/adr/0004-provider-abstraction-pattern.md).

## CI gate

The authoritative gate is the Woodpecker pipeline
(`.woodpecker/ci.yml`), run locally on the committer's machine with Docker
via `ci-local` (or on a Woodpecker server when one is registered). GitHub
Actions is a billing-blocked mirror: its workflows are disabled, its badge
is absent, and it is not part of the merge gate.

- **Local:** `ci-local` (runs `.woodpecker/ci.yml` on a throwaway copy of
  the tree, never the checkout). Exit 0 = green. Equivalent to
  `npm run gate`, plus PostgreSQL integration, frontend, pack/installer
  and e2e smoke jobs.
- **The local gate (`npm run gate`)** runs typecheck → build →
  db:sync:check → lint → format:check → check:migration-compat →
  check:sql-portability → notices:check → adr:index:check →
  check:pack → release:verify --pack → test:installers →
  check:doc-drift → check:release-consistency → **check:quickstart** →
  check:workflows → check:legal-placeholders → backend tests with coverage →
  frontend typecheck/lint/test-with-coverage/build → the end-to-end smoke
  gate (`npm run test:e2e:smoke`).
- **The quickstart gate:** `npm run check:quickstart` runs the command the
  README advertises, in a throwaway directory, and asserts the contract a
  reader is entitled to: exit 0, no log lines on stdout, the five numbers,
  nothing written to the disk, a time budget — and that the output
  documented in the README is the output the command produces.
- **The release state:** `npm run release:doctor` compares the version
  `package.json` announces with the world: a clean tree, a tag for the
  version, the tag on the remote, and — with `--remote` — the package on
  npm and the image in the registry. A release that is announced but not
  published is a command that fails, not a discovery days later.
- **End-to-end smoke:** the gate ends with a Playwright subset — auth,
  portfolio and the WCAG 2.1 AA gate — so the local gate cannot be green
  while the shipped SPA is broken. It needs the Chromium build once per
  machine: `npm run e2e:install`. The full suite stays in CI
  (`npm run test:e2e`). `SKIP_E2E_SMOKE=1` is the only escape hatch and it
  prints a warning in the log.
- **With Docker:** `npm run gate:docker` additionally renders both compose
  stacks, lints Prometheus alert rules, and (when Docker is available)
  starts base+Unbound and prod-overlay to assert `/api/v1/health` on a
  fresh Postgres volume. Run this before any tag or any change to
  compose/Dockerfile/deploy/.
- **Cloud acceptance:** `npm run acceptance:cloud` is the Cloud edition's
  own gate (ADR-0095). It is not part of `npm run gate`; run it before any
  Cloud deploy.
- **Pre-push:** husky `pre-push` → `npm run gate`. Bypass only with an
  explicit `--no-verify`.
- **Done / merge-ready** means the gate is green on the final tree.
  See `~/.agents/CI.md`.
- **Secret scanning:** TruffleHog runs in CI over the pushed diff with
  verification enabled, so any credential-shaped URI in a tracked file is
  reported. Keep database URIs password-free in tracked files
  (`postgresql://<user>@<host>:5432/<db>`); the password goes in a
  separate variable.