Skip to content

Deployment Unknowns & Prerequisites

Things that need to be sourced, provisioned, or decided before a production deployment can go live. None of these exist in the codebase — they were held by the third party and were never handed over.


External services (credentials needed)

These are live third-party integrations the app calls at runtime. Without valid credentials the relevant features will fail silently or error.

ServiceWhat it doesEnv var(s) neededStatus
SendGridTransactional emailSENDGRID_API_KEY✅ Account and key provided by third party — variable entry only
Google reCAPTCHA v3Contact form bot protectionDJANGO_GOOGLE_RECAPTCHA_TOKEN❓ Need site secret
Clear ChecksApplicant background checksCLEARCHECKS_URL, CLEARCHECKS_API_KEY⚠️ Marked deprecated in code (v2.1.0) — confirm if still needed

SendGrid — remaining steps

Credentials are in hand. Before go-live:

  • Update DEFAULT_FROM_EMAIL away from Medical Web Experts <devops@medicalwebexperts.com> to a Nova Home Care address
  • Verify the sending domain in SendGrid (add SPF + DKIM DNS records)
  • Set SENDGRID_API_KEY in the production secrets store

AWS resources (to be provisioned)

These don't exist yet and need to be created in the NHC AWS account.

S3 — two buckets required

The Django backend uses S3 for both static files and user-uploaded media. Two separate buckets are expected:

BucketPurposeACL
Public bucketcollectstatic output, public uploadspublic-read for static prefix
Private bucketPatient/employee documents, PDFsprivate — access via presigned URLs

Env vars: DJANGO_AWS_S3_PUBLIC_BUCKET_NAME, DJANGO_AWS_S3_PRIVATE_BUCKET_NAME, DJANGO_AWS_S3_REGION_NAME, DJANGO_AWS_ACCESS_KEY_ID, DJANGO_AWS_SECRET_ACCESS_KEY

An optional CloudFront distribution can front the public bucket: DJANGO_AWS_S3_CUSTOM_DOMAIN

IAM

A dedicated IAM user or role needs S3 read/write on both buckets. If running on EC2 or ECS, prefer an instance role / task role over long-lived access keys.


The signing certificate (nova.p12)

The app uses pyHanko to digitally sign PDF documents. It expects:

  • A .p12 file at secrets/nova.p12 inside the container
  • The certificate password in PYHANKO_P12_PASSWORD

This is a hard blocker — without it, the app starts and logs in normally but PDF signing fails silently. A user submits a form, the document stays stuck in a pending state indefinitely, and the Celery worker logs the error. No crash, no obvious alert — it just never completes.

Step 1 — identify what type of cert was used

Download any PDF that was signed on the third party's staging environment. Open it in Adobe Acrobat Reader and look at the signature panel:

What Adobe showsCertificate type
Green checkmark, "Certified by..." with a known issuerCommercial cert (DigiCert, GlobalSign, Sectigo, etc.)
Yellow warning, "The identity of the signer is unknown"Self-signed

If you cannot get a signed PDF from the third party's environment, assume self-signed and proceed to Step 3.

Step 2 — request the certificate from the third party

The cert was generated for Nova Home Care — it belongs to the client, not the developer. Request:

  • The nova.p12 file
  • The password used to protect it (PYHANKO_P12_PASSWORD)

If they cooperate, skip to Step 4.

Step 3 — if they won't or can't provide it

If self-signed — generate a replacement. There is no loss of functionality. New documents will be signed with the new cert; existing signed documents remain valid against the old cert (the public key is embedded in each PDF at signing time).

bash
# Run on any machine with OpenSSL installed
openssl req -x509 -newkey rsa:2048 -keyout nova.key -out nova.crt -days 3650 -nodes \
  -subj "/CN=Nova Home Care/O=Nova Home Care/C=US"

# It will prompt for an export password — set one and record it as PYHANKO_P12_PASSWORD
openssl pkcs12 -export -out nova.p12 -inkey nova.key -in nova.crt \
  -name "Nova Home Care Signing"

# Clean up — only nova.p12 is needed going forward
rm nova.key nova.crt

If commercial — purchase a new document signing certificate. The new cert will have a different issuer fingerprint but the app does not care — pyHanko only needs a valid .p12. Existing signed PDFs are unaffected.

Recommended issuers (all support PKCS12 / .p12 export):

IssuerApproximate cost
Sectigo (Comodo)~$100/year
DigiCert~$200/year
GlobalSign~$150/year

Step 4 — deploy the certificate

Never commit nova.p12 to the repo. In production, store it as a binary secret and mount it at runtime:

bash
# Copy to the secrets directory on the EC2 instance
sudo mkdir -p /opt/nhc-portals/django-api/secrets
sudo cp nova.p12 /opt/nhc-portals/django-api/secrets/nova.p12
sudo chmod 600 /opt/nhc-portals/django-api/secrets/nova.p12

Set PYHANKO_P12_PASSWORD in django-api/.env to the certificate password.

Verify it works by running the PDF smoke test in the Smoke Tests checklist before signing off on the migration.


Frontend — what replaces Netlify

The portals .env.development.example references https://develop--novahomecaresite.netlify.app — that's the third party's Netlify deployment. It needs to be replaced.

In production the React/Vite app is a static build (not a dev server). Options:

  • S3 + CloudFront — natural fit since S3 is already used for Django storage
  • Cloudflare Pages — already proven for this org (docs are deployed this way)

VITE_SITE_BASE_URL must be updated to the new domain once decided.


Django secret key

DJANGO_SECRET_KEY must be a long random string unique to production. Never reuse the development value. Generate one:

bash
python -c "import secrets; print(secrets.token_urlsafe(50))"

ALLOWED_HOSTS and CORS origins

Once the production domain is known, set:

  • DJANGO_ALLOWED_HOSTS — the API domain (e.g. api.novavirtual.site)
  • DJANGO_ALLOWED_ORIGINS — the frontend domain (e.g. https://app.novavirtual.site)

The EC2 private IP is auto-detected from the EC2 metadata endpoint and added to ALLOWED_HOSTS automatically for ALB health checks — no manual config needed for that.


Organization tokens

Three org tokens are hardcoded across the codebase and in the testing .env:

TokenOrg
5ae807a7-df99-4bc2-8d51-fa808b81a41eNova Health First, Inc
e9686292-0b70-4019-9ef1-c1a275a9723dEssential Home Health Care
9f66eef3-be72-482b-a6a9-c1eb647367f8Aurora Home Health (also in DJANGO_AURORA_ORG_TOKEN)

These tokens are set in the database via fixtures. Confirm the production database is loaded from the same fixtures and these tokens match.


Summary checklist

  • [x] SendGrid — account and key provided, variable entry only
  • [ ] SendGrid — update sender identity away from medicalwebexperts.com
  • [ ] SendGrid — verify sending domain (SPF + DKIM)
  • [ ] Google reCAPTCHA v3 site key + secret
  • [ ] nova.p12 — request from third party (belongs to Nova HC); regenerate if unavailable
  • [ ] S3 public bucket created
  • [ ] S3 private bucket created
  • [ ] IAM role/user with S3 access
  • [ ] Django secret key generated for production
  • [ ] Decision on frontend hosting (S3+CloudFront or Cloudflare Pages)
  • [ ] Production domains decided (DJANGO_ALLOWED_HOSTS, DJANGO_ALLOWED_ORIGINS, VITE_SITE_BASE_URL)
  • [ ] Clear Checks — confirm deprecated and disable, or provide sandbox/prod key
  • [ ] Database loaded with correct fixtures and org tokens verified

Nova Home Care — Internal Developer Docs