Commit graph

50 commits

Author SHA1 Message Date
Claude
360b6ce112
feat: structured data (JSON-LD) on name detail and pricing pages
Product schema on name pages with brand, offers, URL. BreadcrumbList
on pricing page. Triggers Google rich results and schema.org monitoring
alerts for brand sunrise names. Rate limit headers already provided
by api middleware group (X-RateLimit-Limit/Remaining).

Commit #103.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 13:04:57 +01:00
Claude
1e34701e71
feat: BelongsToWorkspace on NameClaim, DnsTicket, NameActivity
Multi-tenant scoping via CorePHP tenant package. workspace_id column
added to all three tables. Existing records backfilled to workspace 1
(Lethean CIC). workspaceContextRequired=false allows public API calls
without workspace context.

Commit #100.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 12:55:34 +01:00
Claude
d1873dbe09
feat: migrate all API routes to ApiRoutesRegistering
All 6 Mod modules now register API routes via ApiRoutesRegistering
instead of WebRoutesRegistering with CSRF hacks. The api middleware
group (ThrottleRequests + SubstituteBindings, no CSRF/session)
handles everything natively. Website/Api module simplified to just
metrics and homepage. fireApiRoutes() added to Web Boot.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 12:51:53 +01:00
Claude
aebb9b3d5d
feat: CorePHP packages integrated — tenant, commerce, api
Symlinked core-api, php-commerce, php-tenant into app/Core/.
All migrations ran (50 tables). Tenant feature seeder ran.
Workspace 'Lethean CIC' created with admin user Charon and
'Lethean Registrar' namespace. SetupWorkspace artisan command
for repeatable provisioning.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 12:44:43 +01:00
Claude
8f9c1f282e
feat: email notifications on claim approval + OG images for names
ClaimApproved mailable sent when admin approves a claim — dark
themed HTML email with name, next steps, and CTA links. Wrapped
in try/catch so email failure doesn't block approval.

Dynamic SVG OpenGraph images at /names/{name}/og.svg — shows name,
type badge (Registered/Reserved/Gateway/Available), and branding.
og:image meta tag added to name detail pages via @push('head').

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 12:20:43 +01:00
Claude
0241e1f4a6
feat: TestCase base class + test infrastructure
tests/TestCase.php bootstraps app via Core\Boot::app() with kernel
bootstrap. DatabaseTransactions for test isolation. PHPUnit config
with array cache/session. 12 tests written, unit tests pass.
HTTP endpoint tests need chain daemon mock to run standalone.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 12:17:54 +01:00
Claude
3f294340b2
feat: UpdateDnsRecords Action, Prometheus metrics, JSON validation
- UpdateDnsRecords Action: controller method now one-liner, all DNS
  logic in Action with activity logging and edit lock.
- Prometheus metrics at /v1/metrics: chain_height, alias_count,
  claims_pending, dns_tickets, gateways_live. Grafana-ready.
- ValidateJsonRequest middleware: enforces application/json on POST,
  64KB body size limit. Applied to all /v1/* API routes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 12:12:07 +01:00
Claude
ad29a45507
feat: chain:stop command + DNS update activity logging
chain:stop sends SIGTERM and waits for graceful shutdown.
DNS updateRecords now logs 'dns_updated' activity with ticket_id
and records. Claim approve/reject also logged in previous commit.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 12:09:19 +01:00
Claude
3f82c497fd
feat: claim approval/rejection API endpoints
POST /v1/names/claims/{id}/approve — changes status, logs activity.
POST /v1/names/claims/{id}/reject — changes status, logs activity.
Both require auth.api middleware. Validates claim exists and is pending.
Completes the claim lifecycle: submit → review → approve/reject.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 12:07:38 +01:00
Claude
1ef6ed1c7b
refactor: move DNS tickets from Cache to DnsTicket database model
DNS change tickets now persisted in MariaDB via DnsTicket model.
Survives cache clears and container rebuilds. Model has open(),
confirm(), fail() methods and pending/queued scopes. Controller
updateRecords and ticket endpoints refactored. RetryDnsTickets
command queries model instead of cache.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 12:06:00 +01:00
Claude
309599c429
feat: test suite for Names API endpoints
13 tests covering CheckAvailability, SubmitClaim, NameClaim model
scopes, NameActivity logging, and HTTP endpoints. PHPUnit config
added. Tests need TestCase base class setup to run — framework
testing infrastructure TBD.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 11:51:28 +01:00
Claude
6af0d7ea73
feat: API Resources for consistent JSON formatting
NameResource transforms alias data with parsed type, capabilities,
and owner_type (registry/community). ClaimResource formats claim
responses. Lookup endpoint uses NameResource, claim uses ClaimResource
with additional message. Follows CorePHP patterns/building-rest-apis.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 11:49:19 +01:00
Claude
14f4d1fdc0
feat: activity logging for name operations
NameActivity model with log() static method. Stores event, name,
properties (JSON), and hashed IP (GDPR). SubmitClaim action now
logs 'claimed' event. Ready for dns_updated, registered, etc.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 11:46:31 +01:00
Claude
113b228fee
feat: ServiceDefinition for Chain and Names modules
ChainService (code=chain, no deps) and NamesService (code=names,
depends on chain). Ready for CorePHP service registry discovery
when core-api package is installed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 11:44:39 +01:00
Claude
9a36b836a7
feat: schedule DNS ticket retry every minute via ConsoleBooting
RetryDnsTickets command now scheduled everyMinute with
withoutOverlapping. Runs via supervisor scheduler in the container.
Queued DNS changes retry automatically without manual intervention.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 11:43:54 +01:00
Claude
ca11c4ccee
refactor: extract Actions for CheckAvailability, SubmitClaim, RegisterName
CorePHP Actions pattern — single-purpose classes with static ::run().
Controller methods now delegate to Actions. Each Action validates,
executes, and returns typed results. Enables reuse from commands,
jobs, and tests without going through HTTP.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 11:24:27 +01:00
Claude
2b91476cf7
refactor: move pre-registration claims from Cache to database model
Claims stored in Cache were lost on cache clear. Now persisted in
name_claims SQLite table via NameClaim Eloquent model. Auto-generates
claim_id via random_bytes. Scopes: pending(), approved(). Methods:
approve(), reject(). Status page updated to query model.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 11:21:58 +01:00
Claude
9b1a062f2e
fix: revert @cspnonce — Headers Boot not registering directive
The @cspnonce Blade directive isn't available (Headers module not
loading). Reverted to plain <script>/<style> tags. unsafe-inline
in CSP config handles security. Nonces re-added when Headers Boot
is properly integrated.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 11:14:41 +01:00
Claude
8a21996add
security: add CSP nonce attributes to inline scripts and styles
Added @cspnonce to all inline <script> and <style> tags in layout,
explorer, and register views. Enabled nonce generation in headers
config. unsafe-inline kept as fallback. Nonces will activate after
container restart when the Headers Boot registers the Blade directive.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 10:22:38 +01:00
Claude
07051071a4
feat: Sunrise Fast Track — $49 BTC to skip verification queue
Adds paid fast-track option to sunrise page, reserved name detail
pages, and pricing table. Links to Blesta order form for BTCPay
payment. Three clear paths: free DNS verification, free manual
verification, or $49 BTC fast track with immediate registration.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 09:46:20 +01:00
Claude
d83c9094cd
refactor: move /v1/* API routes exclusively to Website/Api module
Production stack has honeypot that null-routes API payloads sent to
the web domain. API routes now only register via Website/Api module
(api.lthn.io). Mod modules stripped to web-only routes. Frontend JS
fetch calls use configurable API_URL for cross-origin API access.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 09:36:59 +01:00
Claude
6b2032c687
fix: exclude API routes from CSRF validation
POST endpoints on /v1/* were returning 419 CSRF mismatch because
$event->routes() wraps routes in the web middleware group which
includes ValidateCsrfToken. External clients (Blesta, curl) can't
send CSRF tokens. withoutMiddleware() on /v1/* prefixes fixes this.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 09:26:54 +01:00
Claude
646fb0602f
refactor: adopt CorePHP lifecycle event patterns in all Mod modules
All 6 Mod modules now use $event->routes() and $event->views() instead
of raw Route:: and app('view')-> calls. Service singletons moved to
FrameworkBooted where appropriate. Website/Api module added for
api.lthn.io domain with proper DomainResolving.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 09:13:34 +01:00
Claude
f1b741da49
feat(names): enrich name detail pages with DNS records + services
Name detail pages now show DNS records from sidechain, ITNS sidechain
registration, services links (DNS/SSL/Proxy), and CIC governance label
for community members. Available names link to claim page.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 08:47:20 +01:00
Claude
1f31444171
feat(names): pre-registration claim system for soft launch
Adds claim/listClaims endpoints so visitors can reserve .lthn names
before chain registration is fully automated. Claims are stored with
email for notification when approved. Admin endpoint lists all claims.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 08:30:23 +01:00
Claude
9b4b6d5264
feat: instant name registration page with live availability check
- /names/register: search → see result → one-click register
- Live API check via JavaScript (no page reload)
- Green "Register now" button links directly to Blesta checkout
- Reserved names link to /sunrise, taken names link to detail page
- Requirements and features shown alongside search
- Autofocus on input, Enter key support

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 08:15:46 +01:00
Claude
a5f28d5f6f
security: fix critical + high code review findings
CRITICAL:
- DaemonRpc: only cache successful responses as stale fallback (not errors)
- Records endpoint: replaced file_get_contents with Http::timeout(3)

HIGH:
- WalletRpc: removed exception message from API response (IP leak)
- Ticket/session IDs: replaced MD5(predictable) with random_bytes (CSPRNG)
- Race condition lock: Cache::add() atomic instead of has()+put()

MEDIUM:
- Block caching: getBlockByHeight cached 1hr (blocks are immutable)
- Sunrise meta description: fixed Blade variable syntax

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 08:08:18 +01:00
Claude
ed300e200e
feat(sunrise): verify then pay claim flow + ownership tiers
- Verify response includes claim_process (4 steps: verify → check → pay → transfer)
- Ownership tiers: free (registry key, limited DNS) vs paid (your key, full control)
- Check response includes purchase_url when verified
- Payment via Blesta/BTCPay completes the claim

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 06:34:26 +01:00
Claude
054b2e6161
feat(sunrise): DNS TXT verification for brand claims (HNS-style)
- GET /v1/names/sunrise/verify/{name} — generate verification token
- GET /v1/names/sunrise/check/{name} — check TXT record across .com/.org/.net/.io/.co.uk
- Token: _lthn-verify.brand.com TXT "lthn-verify={hash}"
- Same process as Handshake TLD claims
- Sunrise page shows both auto (DNS) and manual (email) verification paths
- Automatic claim when DNS record matches

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 06:28:58 +01:00
Claude
fee14f9bbb
fix: sunrise banner links to /sunrise page, enquire button for mailto 2026-04-04 06:20:00 +01:00
Claude
3814182273
fix(seo): fix Blade @context parsing in schema.org markup
- Layout schema wrapped in @verbatim to prevent Blade parsing @context/@type
- Removed per-page schema sections (Blade variables inside @verbatim don't work)
- Org-level schema + OpenGraph + meta descriptions all rendering correctly
- All pages back to 200

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 06:12:09 +01:00
Claude
6a2709fd7e
feat(seo): schema.org rich markup + OpenGraph + meta descriptions
- Organization schema on all pages (Lethean CIC, contact, offers)
- Per-name WebPage schema with Thing identifier (triggers Google Trends)
- Services ItemList schema with 3 Service offerings + pricing
- Sunrise WebPage schema with ItemList of reserved names
- OpenGraph + Twitter Card meta tags
- Canonical URLs
- Per-page meta descriptions via @yield

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 06:06:43 +01:00
Claude
fa771a9422
feat(sunrise): dedicated sunrise period page
- /sunrise page listing all 115 reserved names
- How to Claim: 4-step process with accepted proof types
- Stats: reserved count, active status, end date TBD
- All names as clickable tag cloud linking to detail pages
- Linked from reserved name detail pages
- "Request a reservation" CTA for unlisted brands

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 05:53:57 +01:00
Claude
b28cd85a26
feat(names): sunrise period claim flow + improved available page
- Reserved names show Sunrise Period card with claim CTA
- Claim links to developers@lethean.io with pre-filled subject
- "Proof of brand ownership required" disclosure
- Available names page: feature list + prominent register button
- Fixed HNS → ITNS sidechain label

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 05:45:54 +01:00
Claude
01561b5ecc
fix(names): non-registry wallet = Community Member, not Premium 2026-04-04 05:11:58 +01:00
Claude
af00c60763
feat(names): premium vs registry-managed ownership tiers
- Names with registrar wallet address = "Registry Managed" (green)
- Names with customer wallet address = "Premium — Self-Custody" (amber)
- Shown on name detail pages and directory

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 05:09:39 +01:00
Claude
9675c0fe81
feat(names): rich name detail pages + type badges in directory
- Name detail: owner with @LetheanRegistry/@LetheanTestnet labels
- Type badges: Reserved (amber), Gateway/Service/User (green)
- Capabilities shown as individual badges (vpn, dns, proxy, etc)
- HNS sidechain reference shown when present
- Directory: type column with badges, details column with capabilities
- API lookup link on detail pages

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 03:56:37 +01:00
Claude
994fa0733f
feat(names): API auth + rate limiting on write endpoints
- Bearer token auth middleware on POST /register and /records
- Throttle: 10 registrations/min, 20 DNS updates/min
- Token configurable via API_TOKEN env var (disabled when empty)
- Daemon alias validation: a-z 0-9 . - up to 255 chars

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 03:44:53 +01:00
Claude
c166471d19
feat(names): per-name edit lock prevents concurrent DNS overwrites
- DNS update locks name for 5 min (until block confirms)
- Second edit gets clear "update pending" error (409)
- Lock released when ticket confirmed against chain

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 03:19:01 +01:00
Claude
fc97af878f
fix(names): use pipe separator in dns= format, prevent comma-in-value bug
- dns= entries now separated by | instead of ,
- Commas in TXT values (e.g. SPF records) no longer break parsing
- IPv6 addresses verified safe with splitColon(entry, 3)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 03:17:09 +01:00
Claude
1f29000c11
feat(chain): circuit breaker with stale cache fallback
- DaemonRpc: try/catch with stale cache (1h TTL) when daemon is down
- WalletRpc: try/catch with clear error message
- Health endpoint: status=offline/degraded/critical/low_funds/healthy
- Reports wallet_online, daemon_online, stale flags
- Reduced daemon timeout from 10s to 5s, wallet from 30s to 15s

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 03:06:23 +01:00
Claude
0c5f35c47f
feat(names): reservation lock prevents race conditions
- Cache-based lock on name during registration (10 min TTL)
- Availability check shows reserved: true when locked
- Second registration attempt gets clear error message
- Lock released on permanent failure, auto-expires after 10 min

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 02:55:57 +01:00
Claude
afc955c7b9
feat(names): wallet health endpoint + pre-flight balance check
- GET /v1/names/health — registrar balance, registrations remaining, chain status
- Returns 503 when critically low (< 2 registrations)
- Pre-flight balance check in register endpoint rejects early if wallet empty
- Thresholds: low_funds < 10, critical < 2

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 02:52:34 +01:00
Claude
e351b9deaa
feat(names): background retry for queued DNS tickets
- artisan names:retry-dns command retries queued tickets
- Checks pending tx confirmation against chain
- Tracks ticket IDs in cache for iteration
- Registered via ConsoleBooting event

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 02:41:29 +01:00
Claude
03a45a51d4
feat(names): DNS change queue with ticket tracking
- POST /v1/names/records/{name} returns ticket ID for tracking
- GET /v1/names/ticket/{id} checks status (queued/pending/confirmed)
- Queue gracefully handles busy chain (202 Accepted)
- Ticket auto-checks confirmation against chain alias

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 02:06:38 +01:00
Claude
c46a163bbb
feat(names): DNS records backed by LNS sidechain
- GET /v1/names/records/{name} reads from LNS sidechain (/resolve)
- POST /v1/names/records/{name} writes via update_alias on chain
- Records encoded in alias comment: dns=TYPE:HOST:VALUE,...
- LNS_URL config for sidechain endpoint

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 00:53:49 +01:00
Claude
0899881138
feat(lthn.io): name registration API, Blade views, wallet RPC
- POST /v1/names/register endpoint with wallet RPC integration
- WalletRpc service for alias registration via daemon wallet
- Blade views for homepage, explorer, names directory, network status
- Explorer and Names modules with view namespaces and web controllers
- Pool endpoint graceful offline handling
- Explorer block detail, aliases, search views

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 23:04:27 +01:00
Claude
41a90cbff8
feat: lthn.io API serving live chain data
Fixed: basePath self→static binding, namespace detection, event wiring,
SQLite cache, file cache driver. All Mod Boot classes converted to
$listens pattern for lifecycle event discovery.

Working endpoints:
- /v1/explorer/info — live chain height, difficulty, aliases
- /v1/explorer/stats — formatted chain statistics
- /v1/names/directory — alias directory grouped by type
- /v1/names/available/{name} — name availability check
- /v1/names/lookup/{name} — name details

Co-Authored-By: Charon <charon@lethean.io>
2026-04-03 17:17:42 +01:00
Claude
756be80d04
feat: complete module scaffolding — all 6 modules with controllers, routes, services
Modules built:
- Home: landing page with live chain stats and service directory
- Chain: DaemonRpc singleton, config, events
- Explorer: web + API controllers (block, tx, alias, search, stats)
- Names: TLD registrar (availability, lookup, directory, registration)
- Trade: DEX controllers + API (config, pairs, orders)
- Pool: dashboard + PoolClient service (stats, blocks, payments, miner)

Infrastructure:
- composer.json: lthn/lthn.io deps (core/php + laravel 12)
- Dockerfile: FrankenPHP with Caddy
- Caddyfile: PHP server config

Co-Authored-By: Charon <charon@lethean.io>
2026-04-03 16:26:17 +01:00
Claude
77cc45dd83
feat: lthn.io CorePHP app — TLD website + blockchain services
Modules:
- Chain: daemon RPC client (DaemonRpc singleton, cached queries)
- Explorer: block browser, tx viewer, alias directory, search, stats API
- Names: .lthn TLD registrar portal (availability check, lookup, directory)
- Trade: scaffold (DEX frontend + API)
- Pool: scaffold (mining pool dashboard)

Replaces 5 Node.js containers (5.9GB) with one FrankenPHP app.
Built on CorePHP framework pattern from host.uk.com.

Co-Authored-By: Charon <charon@lethean.io>
2026-04-03 16:13:55 +01:00