aform
An Airtable Forms clone built around a queue-decoupled write path and a hardened, script-driven deployment flow.
aform lets you build forms, share public links, collect submissions, and export them as CSV: a lightweight Airtable Forms clone. It was built and operated with a small cohort team as part of the DevOps Institute program, and the interesting part isn't the form builder itself, but the architecture and operations underneath it: a decoupled write path, secrets pulled from AWS at runtime, and a deployment flow hardened enough to run unattended.
Architecture
The web server returns a response as soon as a submission is published to RabbitMQ; the worker persists it to Postgres asynchronously, with manual ack/nack and requeue on failure.
Tech stack
Application
Data
Messaging
Cloud
Observability
Ops
Deployment & operations flow
- 1
Provision EC2
A public and private EC2 pair is stood up with IAM instance profiles and Route 53 A records. There's no CI system here; deploys are script-driven.
- 2
Bootstrap internal TLS
A self-signed CA is generated and distributed via S3 so Postgres and Redis traffic between the two hosts is encrypted.
- 3
Build & release
Linux binaries are built and rsynced to a timestamped release directory, then symlink-swapped in: a zero-downtime release pattern that also makes rollback trivial.
- 4
systemd + reverse proxy
`aform` and `aform-worker` run as systemd units under a restricted-sudo OS user; Nginx + Certbot terminate TLS and reverse-proxy to the app.
- 5
Harden the hosts
UFW (deny-by-default) and a hardened sshd config on both instances; RabbitMQ's default guest user is deleted.
- 6
Back up & validate
A cron job dumps Postgres to S3 every 10 minutes, and a k6 load test (1,000 virtual users, p95 < 800ms) exercises the real submit path against the live domain.
Highlights
- Form submissions publish to RabbitMQ and return immediately; a separate worker persists them to Postgres, decoupling public response time from database write latency.
- Every backing service (database, cache, queue) independently loads its own connection secret from AWS Secrets Manager at runtime, instead of static .env credentials.
- Image uploads are progressively re-compressed and downsampled until they're under 2MB, with a choice of public or presigned-private S3 delivery.
- Prometheus metrics, including pre-computed p50/p90/p99 latency and error-rate gauges, are exposed on a separate port, decoupled from the main app port.
- Releases are symlink-swapped, so rollback is just repointing the symlink to the previous release directory.
- A real k6 load test against the live environment backs up the performance claims, not just a description of intended behavior.