Devlog

Creodrop isn't available yet — we're still building it. This is a look behind the curtain: raw updates, technical decisions, and progress as we work toward launch.

Get notified with updates and when Creodrop goes live.

Where things stand

April 14, 2026

Component Tech Status
APINode.js + Express + TypeScriptProduction
Control panelNext.js 16 + shadcn/ui + TailwindProduction
Admin panelNext.js + shadcn/uiProduction
SSH gatewayGoDevelopment
CLINode.js (@creodrop/cli)Development
Drupal imagePHP 8.4 + Nginx + SupervisordProduction
Admin guideAstroDevelopment
InfrastructureDocker Compose + Traefik v3.6Production
Platform DBPostgreSQL 16Production
Tenant DBMySQL 8.0Production
Cache/QueueRedis + BullMQProduction

Production lives on a Linode 8GB in Chicago: panel.creodrop.com, api.creodrop.com, demo.creodrop.com.

By the numbers

First commit
January 2, 2026
Days with commits
25
Total commits
140+
Services
7
Languages
TypeScript, Go, PHP, SQL, Shell
Tests
159 unit + Playwright e2e suite
Worst day
Jan 17 — first prod deploy, 9 fix commits
Biggest day
Feb 3 — three admin panel phases in one session
Container theme
UFO / Project Blue Book

Timeline

Production hardening and e2e tests

A full day of production prep across the stack.

Testing: added a Playwright e2e suite covering the full platform — signup, site creation, deploys, admin flows, the works. Catching regressions before users do.

Infrastructure: rewrote the production deploy.sh to use IMAGE_TAG and DOCKER_GID for cleaner image pinning and container permissions. Dropped dnsmasq from production — it's a local-dev-only convenience.

Tenant isolation: refactored Redis so each site gets its own key prefix instead of relying on DB SELECT. More scalable and plays nicer with managed Redis. The Drupal image now honors the prefix for cache isolation too, plus fixes for the installer redirect and dev-mode cookies.

Fixes and DX: SSH gateway now exits exec cleanly when command output ends (was hanging on stdin close). The control panel detects production via APP_ENV instead of NODE_ENV. The API cancels stale redis-enable jobs on site delete and hides soft-deleted sites from listings. Auth auto-promotes ADMIN_EMAIL on register/login, and dev-mode deploy endpoints skip branch/tag validation so local testing doesn't fight you.

Local dev DNS

Added dnsmasq for wildcard DNS so *.creodrop.local just works without editing /etc/hosts for every new site. Had to fight systemd-resolved over port 53, fixed it by disabling the stub listener.

Local dev now runs at *.creodrop.local:8880.

Everything day

A lot landed at once:

S3 storage for site backups. Soft delete with 30-day retention so deleted sites aren't immediately gone. Environment sync UI. Forgot-password flow. Admin bypass for impersonating users (support tool). Account management and domain pages in the admin panel. Multi-target Dockerfile for optimized builds. Error boundaries across the control panel. SSH gateway updates.

Also wrote a full QA test plan and updated the admin guide to cover all the new features.

Git push-to-deploy

The feature I was most excited about: git push deploys, similar to other managed Drupal hosts. New Dockerfiles for the pipeline, started the image selection system, wrote deployment docs.

Redis, queues, and deploy promotion

Connected Redis (bluebook-mothman) for caching and as the BullMQ job queue backend. Replaced console.log with structured logging. Built the deploy promotion system so deployments can move between environments (dev → staging → production).

Started the admin guide as an Astro docs site, and ran an architecture review to find gaps before building more.

Developer tier pivot

After sitting with the product for a while, I decided to go after a second market: developers who want SSH access, Git workflows, and real deployment pipelines but don't want to pay enterprise hosting prices.

Started building:

  • An SSH gateway in Go (ssh-gateway/, container: bluebook-area51). Chose Go over Node.js for concurrency since this service routes SSH connections to the right Drupal container based on a {shortUuid}-{env} username format.
  • A CLI tool (cli/, published as @creodrop/cli).
  • The first unit tests. These eventually grew to 159, covering presets, Docker naming, MySQL naming, SSH keys, deploy tokens, git config, and deploy log sanitization.

Admin panel polish

Went back and tightened up the platform management features from the February 3 sprint. Rough edges from building that fast.

Admin panel build day

Finished three full phases in one session. This was a long day.

Phase 2 (the app itself): admin auth via NextAuth, login page with rate limit countdown, collapsible sidebar, dashboard with metrics and charts, audit log viewer with filters and modals, provisioning history.

Phase 3 (platform management): customer list with search and filters, customer detail pages with tabs, customer actions (suspend, delete, etc.), site list and detail pages, container health status, site restart, streaming container logs, soft delete.

Phase 4 (monitoring): health service pulling CPU/memory/disk metrics, monitoring dashboard with color-coded thresholds, alert rule system with CRUD API and an evaluation engine, email notifications via Resend, alert rule wizard UI, alert history page.

Admin panel planning and foundation

Shifted to the admin panel, the internal tool for actually running the platform. Did the planning first: v1 requirements, a 4-phase roadmap. Then built Phase 1:

  • Database migrations for admin flags and audit logs
  • Admin/audit operations in the PostgreSQL service
  • Rate limiting on the login endpoint
  • ADMIN_EMAIL config to bootstrap the first admin user
  • requireAdmin middleware
  • Audit logging middleware

Started on Phase 2's dashboard stats queries before stopping for the day.

Account management

Cleaned up account management on both the API and dashboard sides. Users could now manage their details and view their sites without the interface fighting them.

Google and GitHub OAuth

Added social login through NextAuth.js v5, Google and GitHub providers. Built the OAuth user lookup endpoint, wired up buttons on the login and registration pages, re-enabled email verification on prod.

Also gave Redis its container name: bluebook-mothman. Actual Redis integration came later.

Site provisioning works

This was the day the product loop closed. You could sign up, create a Drupal site, and see it running. Auth worked on prod, unauthenticated users got redirected properly, status badges showed up on site cards, custom domains worked, and Drupal's trusted host patterns were configured.

Not pretty yet, but functional end-to-end.

Auth on production

Same problems, different environment. Tested the auth flow end-to-end on prod, fixed redirect issues (the "sighting redirect", staying on theme), debugged header forwarding through Traefik, and switched from JWE to plain JWT. Simpler, fewer things to break.

Commit message of the day: "need moar bits", which turned out to be a key size issue.

Auth debugging

A full day fighting authentication. Drupal site path routing was broken, dev URLs needed securing, and I went back and forth on JWT vs JWE before settling on an approach. The commit message "back to working dev" says it all.

DNS and domains

Added a DNS settings UI, fixed domain routing on production, and wrote instruction pages so users know how to point their domains. Some general dashboard cleanup too.

Email verification

New users now get a verification link via Resend before their account activates. Straightforward but necessary.

API security

Locked down the API for production: security headers, access controls. The kind of thing you forget until your site is public.

First production deploy

The day everything had to work on a real server. Nine commits, each one fixing whatever broke next:

  • Docker config mismatches (twice)
  • Traefik routing failures, needed a version bump
  • PostgreSQL healthcheck pointed at the wrong database name
  • Local defaults didn't match production
  • SSL certificate issues
  • API routing through Traefik needed restructuring
  • Traefik dashboard was wide open

By end of day, panel.creodrop.com and api.creodrop.com were live on Linode. Exhausting, but it worked.

Account and site flows

Built out account settings and the site creation wizard. A user could now walk through setting up a Drupal site from the dashboard, even if nothing happened on the backend yet.

Control panel takes shape

The customer-facing Next.js dashboard got its first real pages: login, registration, dashboard layout, DNS docs, migration files, account and site setup. The container earned its name: bluebook-mkultra.

API sprint

Built most of the API endpoints in one sitting. Express + TypeScript, handling site provisioning, user management, all the CRUD. Also started the control panel frontend the same day.

Infrastructure starter

Got Docker Compose wired up with the initial service definitions and networking. Named the first three containers:

  • bluebook-airspace (Traefik reverse proxy)
  • bluebook-hangar18 (MySQL for tenant databases)
  • bluebook-majestic (PostgreSQL for the platform database)

First commit

Started the repo. Codename: Project Blue Book. The UFO/high-strangeness naming convention for containers started as a joke and just... stuck.

Want to follow the journey?

Subscribe for updates as we build Creodrop in public.