Skip to content

Releases: cardano-onboard/platform

Onboard.Ninja DIY v1.3.0-beta

Pre-release

Choose a tag to compare

@Crypto2099 Crypto2099 released this 23 Aug 13:02

Measuring onboarding

Claim counts tell you a campaign was used. They don't tell you whether it
worked.

Every campaign now has an Onboarding panel that answers the question the
platform exists for: did this airdrop bring anyone new onto Cardano, and did
they do anything afterwards? For each claimant wallet it reads public chain data
and reports whether the wallet existed before the claim, whether it later sent a
transaction of its own, and whether it delegates to a stake pool.

Activation is deliberately strict. The wallet has to appear as an input to a
later transaction, not just receive one — otherwise anyone could inflate their
own activation rate by sending more tokens to their own claimants.

The observation window sits with the numbers rather than in a footnote, because
an activation rate a week after an event and the same rate three months later
are completely different claims.

Analysis runs in the background and can be re-run as wallets mature. Your own
test claims can be flagged so they stop dragging the percentages down. On a
self-hosted install with no queue worker, run it directly:

php artisan onboard:analyze "My Campaign"

It uses Koios, which needs no account, and works on
mainnet, preprod and preview. Set KOIOS_API_TOKEN for a higher rate limit on
large campaigns.

Verification. Checked against an event campaign whose results were already
published:
66 claimant wallets, 5 operator tests, 61 genuine attendees, 34 newly onboarded
(55.7%), 17 of those 34 later transacting for themselves (50%). The built-in
analysis and the standalone tooling those figures came from agree on every
number.

Deleting codes

Codes can be deleted individually, as a selection, or as every unclaimed code in
a campaign — the last being the realistic fix for a bulk import that was wrong
from the start.

Claimed codes are never deleted. Their claims are the record that someone was
paid. In a mixed selection the claimed ones are kept and reported rather than
failing the whole request, so a batch that saw a couple of early claims is still
clearable.

Exporting claims

Export claims downloads every claimed address as CSV, with the onboarding
classification alongside where an analysis has run: new or established, prior
transaction count, activation, delegation and pool.

Dashboard

Campaign search across name, description, network and status. The list also fits
small screens properly now, which is where a campaign actually gets checked
during an event.

Documentation

New FAQ,
troubleshooting guide,
support page and a
guide to
measuring onboarding.
The troubleshooting guide covers installation failures that have actually
happened: a host database holding the MySQL port, a stale route cache blanking
the home page, a mail driver that throws because its HTTP client was never
installed, and assets blocked by the content security policy when served from a
separate domain.

Fixes carried from 1.2.4-beta

  • Filesystem operations resolve the configured disk instead of assuming S3, so
    self-hosted installs using local storage work as intended.
  • Bulk code uploads are signed against the configured disk.

Security backlog

Five hardening items from the public backlog are verified and closed in this
release:
content security policy, consolidated frame options, hidden server version,
cross-origin and permissions policies, and content-type options on static
assets. Cross-Origin-Embedder-Policy remains opt-in per deployment, because
require-corp breaks cross-origin assets that do not send their own CORP
header.

Tests

258 PHPUnit (671 assertions) and 73 Vitest, up from 209 and 54 in v1.2.3-beta.

Onboard.Ninja DIY v1.2.3-beta (Milestone 3)

Choose a tag to compare

@Crypto2099 Crypto2099 released this 20 Jul 19:56

Milestone 3 — the public launch release. This is the largest update since the
project went open source: a full token-metadata system, print-ready QR export,
campaign analytics, a documentation site, and a substantial overhaul of the
self-hosted Docker experience.

If you self-host, read the Upgrade Notes at the bottom — this release
contains breaking changes to the Docker setup, all of them fixes for things
that were quietly broken before.


Getting started just got a lot shorter

New installs are now two commands:

git clone https://github.com/cardano-onboard/platform.git
cd platform
./quickstart.sh
docker compose up -d --build

quickstart.sh generates everything that has to be unique to your install —
the Laravel APP_KEY, both MySQL passwords, and your admin login — writes them
to .env with 600 permissions, and refuses to overwrite an existing config
unless you ask it to. Use --yes for unattended installs and
--port 8082 if 8080 is taken.

The previous instructions told you to copy a template and fill in the blanks.
In practice that produced a container that failed on boot, for reasons covered
in the fixes below.

Token metadata & the known-asset registry

Reward tokens can now be picked by ticker instead of raw policy/asset hex.

  • known_assets registry, backed by the Koios token registry. Lookups are
    registry-first: served from the local table, falling back to Koios only for
    an unknown token, then cached.
  • Autocomplete ranked by usage so common tokens surface first.
  • Scheduled sync (assets:sync-registry, every 6 hours) pulls the full
    registry — roughly 7,900 mainnet and 500 preprod tokens. The sync retries
    with backoff and fails loudly rather than silently truncating.
  • Decimal-aware amounts throughout. On-chain values are base units; the UI
    now divides by the token's decimals for display, and converts human input
    back to base units on code creation. No more counting zeros.
  • Seeded defaults: HOSKY, MIN, SUNDAE, iUSD, DJED, USDM on mainnet;
    tDRIP and tUSDM on preprod.

Print-ready QR export

Export a campaign's claim codes as QR codes for printing on cards, flyers, or
badges. Generation is idempotent — re-running won't duplicate or churn stored
files — and works against both local disk and S3-compatible storage.

Campaign analytics & reward visibility

  • Performance charts on the campaign page: claims over time, at a glance.
  • Expandable reward details per claim code, with token metadata resolved
    lazily so the list stays fast.
  • Branded wallet views showing token logo, human-readable name, and
    decimal-formatted amounts, replacing the raw hex tables.

Documentation site

A full VitePress documentation site now covers setup, configuration, campaigns,
codes and rewards, claiming, monitoring, and an API reference — with separate
getting-started paths for self-hosted and SaaS.

License

Onboard.Ninja is now released under the Apache License 2.0 (previously MIT).
Apache 2.0 keeps the same permissive, business-friendly terms while adding an
explicit patent grant and clearer contribution and attribution provisions. See
the LICENSE and NOTICE files for full terms.

Security

  • Claim codes are now generated from independent random draws. The previous
    scheme derived codes in a way that reduced effective entropy. Existing codes
    keep working; newly generated ones are stronger.
  • Content Security Policy is now configuration-driven
    (config/security.php) and enforced in local development rather than
    disabled, so violations surface before they reach production.

Self-hosted fixes

Several of these were preventing a clean Docker install from working at all.

  • APP_KEY is now required, and the container says so. The old entrypoint
    claimed to auto-generate a key, but the generated value was written to a file
    the running process would never read — so the app cached an empty key and
    returned a 500 on every request. Startup now fails immediately with
    instructions instead. Auto-generating per boot was deliberately not restored:
    a key that changes on restart invalidates sessions and makes previously
    encrypted data unreadable.
  • Blank database passwords no longer produce an unfixable install. Compose
    substituted a default when DB_PASSWORD was empty, so MySQL initialised with
    one password while the app was handed another — a permanent
    Access denied for user 'onboard' that no amount of editing .env could
    resolve. Empty values now abort at startup.
  • Host ports are configurable. APP_PORT, DB_HOST_PORT and
    REDIS_HOST_PORT are set in .env; there is no longer any reason to edit
    docker-compose.yml.
  • MySQL and Redis now bind to 127.0.0.1 by default. They were previously
    published on all interfaces, which on a public VPS exposed the database to
    the internet. See Upgrade Notes if you rely on remote access.
  • .dockerignore added. The build context previously included everything,
    meaning a local .env could be baked into image layers.
  • Fixed a blank home page on self-hosted installs. The self-hosted build
    ships a reduced route table, and the frontend referenced routes that only
    exist on the hosted edition. Because the route helper throws on an unknown
    name, this blanked the landing page and every authenticated page. Those
    references are now guarded, with regression tests covering the reduced route
    table.
  • Known-asset endpoints are now routed in the self-hosted build. The
    controller shipped but its routes did not, so token lookup failed at runtime.
  • Corrected repository URLs throughout the README and docs.

Upgrade Notes

APP_KEY must be set. If your .env has a blank APP_KEY, the container
will now stop on startup rather than serving errors. Generate one with
openssl rand -base64 32 and prefix it with base64:, or run
./quickstart.sh. Keep the value stable — changing it logs everyone out and
makes previously encrypted data unreadable.

Database passwords must be non-empty. Blank DB_PASSWORD or
DB_ROOT_PASSWORD now aborts startup instead of silently diverging from what
MySQL was initialised with.

MySQL and Redis are no longer reachable from other machines by default. If
you depend on remote access, set DB_BIND=0.0.0.0 / REDIS_BIND=0.0.0.0 in
.env — but use strong passwords and a firewall first.

Changing database passwords requires care. MySQL only applies
DB_PASSWORD when it initialises an empty data directory. On an existing
install, changing it in .env has no effect and will lock the app out. Either
change it inside MySQL:

docker compose exec mysql mysql -u root -p<OLD_ROOT_PASSWORD> \
  -e "ALTER USER 'onboard'@'%' IDENTIFIED BY '<NEW_DB_PASSWORD>';"

or start fresh with docker compose down -v (this destroys all data).

Seed the known-asset registry after upgrading, so reward tokens can be
picked by ticker:

docker compose exec app php artisan db:seed --force

Known issues

  • The known-asset registry is not seeded automatically on first boot; run the
    command above. This will be folded into container startup in a later release.
  • ADMIN_PASSWORD remains in .env after the admin account is seeded, and is
    re-applied on every container restart — so changing your password in the app
    is reverted on the next restart. A dedicated command to manage the admin
    account is tracked for the next release.

Full documentation: https://cardano-onboard.github.io/platform/

Onboard.Ninja DIY v1.1.0-beta (Milestone 2)

Choose a tag to compare

@Crypto2099 Crypto2099 released this 10 Jun 18:12

Onboard.Ninja DIY — v1.1.0-beta

Self-hosted Cardano airdrop platform. Run your own claim portal end-to-end:
upload a CSV of codes, generate QR codes, and let claimants redeem rewards
straight from a wallet.

This release builds on the initial DIY drop with substantial work on testing,
security, and operator ergonomics.

Highlights

  • Pluggable transaction backend. The TransactionBackend contract lets
    you wire in your own Cardano transaction service. Three drivers ship in
    the box: phyrhose (the hosted service the SaaS uses), proxy (routes
    through a configurable HTTP proxy), and null (no-op for local
    development and CI).
  • Docker-first deployment. Multi-stage Dockerfile plus
    docker-compose.yml get you to a working stack with one command. An
    .env.docker template covers every knob you'll need.
  • First-run admin seeding. Set ADMIN_EMAIL / ADMIN_PASSWORD and the
    seeder provisions your owner account. No registration endpoint, no public
    signup — DIY operators control who logs in.
  • Configurable limits. File size, code count, and per-IP / per-campaign
    rate limits are all driven by env vars, so you can match your hardware and
    audience without touching code.
  • Node 22 LTS across CI and the Docker image.

Configuration

Everything operator-tunable lives in .env. Notable knobs added in this
release:

Variable Default Purpose
UPLOAD_MAX_FILE_SIZE 10485760 CSV upload size (bytes, default 10 MB)
UPLOAD_MAX_CODES 10000 Codes per campaign
CLAIM_RATE_PER_IP 60 Claim requests per minute per IP
CLAIM_RATE_PER_CAMPAIGN 120 Claim requests per minute per campaign
ADMIN_EMAIL / ADMIN_PASSWORD — First-run admin credentials
TRANSACTION_BACKEND null Backend driver (phyrhose, proxy, null)

See .env.docker and config/cardano.php for the full set.

Testing & Quality

The DIY release ships with the same test suite the hosted version runs in CI:

  • 224 automated tests — PHPUnit (164), Vitest (40), Dusk E2E (20)
  • 56% PHP coverage, gated at 50% in CI
  • 28 security tests covering XSS, SQL injection, auth bypass, CSRF, mass
    assignment, and cross-user authorization on every authenticated endpoint
  • OWASP ZAP baseline scan clean of high-severity findings
  • k6 load tests with reproducible profiles for sizing your own deployment

Run them locally with php artisan test, npm run test, and
php artisan dusk.

Hardware Sizing

Load-tested across three resource profiles so you can pick the right box:

Profile RAM Claims/sec Dashboard p95 Concurrent users
Minimum 1.5 GB 26.6 14 ms ~10
Recommended 2.5 GB 72.5 16 ms ~30
Comfortable 4.5 GB 126.4 22 ms ~50

Numbers are from a sustained k6 run against the claim API; your mileage will
vary with backend latency.

Bech32 Address Validation

Wallet address validation now follows BIP-173 charset
([023456789acdefghjklmnpqrstuvwxyz]) and CIP-19 length rules, rejecting
typos and obviously-malformed addresses before they hit the transaction
backend.

Security Hardening

  • ULIDs (not auto-increment IDs) on all user-facing models
  • Soft deletes everywhere it matters
  • Secret fields (key, skey, vkey) marked $hidden so they never leak
    through Inertia props
  • CampaignPolicy enforces owner-only access; controller authorizeResource
    short-circuits cross-user access at the framework level
  • Security headers on every response: X-Content-Type-Options: nosniff,
    X-Frame-Options: DENY, Referrer-Policy: strict-origin-when-cross-origin,
    and HSTS on HTTPS

Getting Started

git clone https://github.com/cardano-onboard/platform.git onboard
cd onboard
cp .env.docker .env
# edit .env — set APP_KEY, DB password, ADMIN_EMAIL/PASSWORD, backend creds
docker compose up -d
docker compose exec app php artisan migrate --seed

Full instructions, including running without Docker, are in README.md.

Known Limitations

  • The phyrhose driver targets Phyrhose, a hosted
    transaction-submission service by Andrew Westberg that the Onboard.Ninja
    SaaS uses for token distribution. Using it requires your own JWT and
    network ID. If you'd rather not depend on a hosted service, implement the
    TransactionBackend contract against your own infrastructure and register
    it in AppServiceProvider::resolveBackend().
  • Single-operator model — there's no multi-tenant or team-account support in
    the DIY build. Each instance is one organization.
  • Beta software. Battle-tested in CI and load tests, but production
    deployments should be monitored closely. Bug reports welcome via GitHub
    Issues.

Contributing

CONTRIBUTING.md covers the dev setup, test commands, and PR conventions.
Issue templates for bug reports and feature requests are in
.github/ISSUE_TEMPLATE/.


Built on Laravel 10, Vue 3, Vuetify 3, and Inertia.js.

v1.0.2-beta.3

v1.0.2-beta.3 Pre-release
Pre-release

Choose a tag to compare

@Crypto2099 Crypto2099 released this 08 Apr 03:34

Changes

  • Fix platform test failures (password confirmation/update tests excluded)

v1.0.1-beta.2

v1.0.1-beta.2 Pre-release
Pre-release

Choose a tag to compare

@Crypto2099 Crypto2099 released this 20 Mar 02:44

Onboard.Ninja DIY — self-hosted Cardano airdrop platform (public beta).