Interactive booth activation where attendees write a physical postcard, enter the destination zip code into a terminal CLI, and watch Snowflake compute the journey distance via geospatial SQL — then chat with Cortex AI about the live event dataset.
⚠️ Requires a Standard/Enterprise Snowflake account — trial accounts will not work. The Cortex AI Q&A step callsSNOWFLAKE.CORTEX.COMPLETE, which is blocked on trial accounts (399258 (0A000): AI function COMPLETE is not available for trial accounts). The CLI auto-detects this and skips the Q&A so the postcard flow still runs, but you lose the headline AI demo.
snowflake-postcard/
├── init_db.sql ← Run once in Snowflake to set up DB, table, views, POSTCARD_USER
├── cli_app.py ← CLI app run on each booth laptop (this is the attendee experience)
├── tv_map.py ← Streamlit real-time map for the TV display
├── requirements.txt
├── setup-laptop.sh ← Per-laptop booth setup (one-time)
├── start-postcard.sh ← Per-attendee launcher (what the `postcard` alias runs)
├── postcard_rsa.p8 ← Booth private key (committed; rotate after each event)
├── postcard_rsa.pub ← Booth public key (also embedded in init_db.sql)
├── .env.example ← Template; setup-laptop.sh creates .env for you
└── README.md
Install the ZIP-code Marketplace dataset and run the init script.
a) Install the ZIP-code dataset. In Snowsight: Data Products → Marketplace → search "U.S. ZIP Code Metadata with Geometry" by SFR Analytics → Get → override the database name to exactly FREE_ZIPCODES_DB. Grant access to SYSADMIN and POSTCARD_ROLE (the role created in step b).
b) Run init_db.sql as ACCOUNTADMIN. Creates the warehouse, database, table, views, the POSTCARD_USER booth user, and registers the booth's RSA public key on it.
snow sql -f init_db.sqlgit clone https://github.com/MLH/snowflake-postcard && cd snowflake-postcard
./setup-laptop.shsetup-laptop.sh does five things:
- Adds a
postcardconnection to~/.snowflake/config.toml(keypair auth pointing atPOSTCARD_USER) - Creates
.envwith the absolute path to the booth private key - Creates a Python venv and installs
requirements.txt - Adds a
postcardshell alias to~/.zshrcand~/.bashrcso volunteers can just typepostcard - Smoke-tests the connection
Open a new terminal (so the alias loads) and you're done.
postcard # aliased to start-postcard.sh — activates venv + runs cli_app.pyThe attendee enters their destination zip, sees the journey distance, asks Cortex an AI question about the live data, and the next attendee picks up where they left off.
source .venv/bin/activate
streamlit run tv_map.pyAuto-refreshes every 4 seconds. Shows KPI metrics, a great-circle arc map from SF to all destinations, state leaderboard, and recent entries.
Every booth laptop authenticates as the same POSTCARD_USER via the same RSA private key. No password (no rotation drift, no policy rejections), no browser flow (no per-attendee OAuth popups), no MFA prompts.
The private key is committed to the repo, so anyone with repo access (current or future) can use the booth credential. After each event, rotate:
# 1. Generate a fresh keypair
openssl genrsa 2048 | openssl pkcs8 -topk8 -inform PEM -out postcard_rsa.p8 -nocrypt
openssl rsa -in postcard_rsa.p8 -pubout -out postcard_rsa.pub
# 2. Copy the new public key body (between BEGIN/END PUBLIC KEY, no newlines)
# into init_db.sql's ALTER USER ... SET RSA_PUBLIC_KEY = '...'
# 3. Push the new key to Snowflake (zero-downtime — Snowflake supports two
# active public keys per user via RSA_PUBLIC_KEY + RSA_PUBLIC_KEY_2)
snow sql -f init_db.sql
# 4. Commit + push the updated postcard_rsa.p8 / postcard_rsa.pub / init_db.sql
git add postcard_rsa.p8 postcard_rsa.pub init_db.sql && git commit -m "Rotate booth keypair"Old git history still contains the old key — if you need to invalidate it fully, run ALTER USER POSTCARD_USER UNSET RSA_PUBLIC_KEY after laptops are off the old key.
| Feature | Where Used |
|---|---|
ST_MAKEPOINT |
Build point geometry from lat/lon |
ST_DISTANCE |
Great-circle distance in metres → miles |
ST_MAKELINE |
Build LineString flight path |
GEOGRAPHY column type |
Stores the arc path in postcard_entries |
SNOWFLAKE.CORTEX.COMPLETE |
AI Q&A grounded in live data |
| Marketplace data | FREE_ZIPCODES_DB.PUBLIC.ZIP_CODE_META_SHARE (SFR Analytics) |
| MVCC | Safe concurrent INSERTs from all booth laptops |
The CLI uses mistral-large2 by default (widely available across regions). To change, edit cli_app.py → ask_cortex().
Database 'FREE_ZIPCODES_DB' does not exist or not authorized
→ Either the Marketplace listing isn't installed yet (step 1a), or it was installed under a different database name. Re-install and override the database name to exactly FREE_ZIPCODES_DB, and grant access to POSTCARD_ROLE.
JWT token is invalid when cli_app.py connects
→ The booth public key isn't registered on POSTCARD_USER. Re-run init_db.sql as ACCOUNTADMIN; check DESC USER POSTCARD_USER and confirm RSA_PUBLIC_KEY is set.
AI function COMPLETE is not available for trial accounts
→ Expected on trial accounts. The CLI auto-detects this and skips the Q&A step. To use Cortex, upgrade the Snowflake account.
Setup script fails with 'snow' CLI not found
→ Install with brew install snowflake-cli or pipx install snowflake-cli.
postcard command not found after running setup-laptop.sh
→ The alias was added to your rc file but the current shell didn't pick it up. Open a new terminal, or run source ~/.zshrc.