Platform Architecture
Maica Apps is built on enterprise-grade AWS infrastructure, designed specifically for Salesforce users. Here is exactly how your data is stored, protected, and kept available.
Platform pillars
Containerised Next.js application running on Amazon ECS (EC2-backed). Application Load Balancer (ALB) terminates TLS and routes traffic. Database: Amazon Aurora PostgreSQL 15 in a Multi-AZ cluster (writer + reader endpoints) in ap-southeast-2. Static uploads stored in Amazon S3 with server-side encryption. All compute and storage stays within the AWS ap-southeast-2 (Sydney) region — no cross-region replication.
NextAuth v5 with a JWT session strategy. Sessions are stored in signed, HttpOnly, Secure cookies — never in localStorage or sessionStorage. Magic link tokens are single-use, expire in 15 minutes, and are bcrypt-hashed before storage. OAuth flows (Google, GitHub) use provider-issued tokens; Maica never stores your OAuth password or refresh token. Middleware validates the JWT on every protected request at the Edge before the request reaches a server.
Access is gated by an AllowedIdentity table — admins explicitly allowlist individual emails or entire domains. Super-admins are defined via the ADMIN_EMAILS environment variable and bypass the allowlist. All API routes are protected by session middleware; admin endpoints additionally verify the requester's email against the super-admin list. Workspace-level isolation: every user and team operates within a workspace boundary that is enforced on every DB query.
Aurora PostgreSQL storage is encrypted at rest with AWS-managed KMS keys. S3 buckets use SSE-S3 encryption. All database credentials, OAuth client secrets, and API keys are stored in AWS Secrets Manager and injected into the container at runtime — they are never committed to source code or baked into the Docker image. Database connections enforce TLS in transit (rejectUnauthorized: false for RDS certificate rotation compatibility). Sequelize parameterised queries prevent SQL injection throughout.
Aurora Multi-AZ provides automatic failover (typically under 30 seconds) to a standby replica in a separate Availability Zone. The ALB performs continuous health checks against /api/health; unhealthy targets are removed from rotation automatically. ECS rolling deployments ensure the old container keeps serving traffic until the new version passes health checks. Application tables are managed by Sequelize alter-sync — new columns are added non-destructively without dropping existing data.
All transactional email is delivered through Amazon SES. Custom sending domains are verified using a TXT identity record plus three DKIM CNAME records, enabling full DKIM/SPF signing. Daily send quotas are enforced per workspace; accounts that exceed thresholds or trigger bounce/complaint events are automatically suspended with an explanatory reason stored in the database. Reply-to and From addresses are configurable per workspace but must use the verified sending domain.
Salesforce connections use the OAuth 2.0 PKCE flow — Maica receives an access token and refresh token that are stored encrypted at rest per user (SFConnection model). Maica never asks for or stores your Salesforce username or password. Token refresh is handled transparently in the background. API calls to Salesforce are proxied server-side; the token is never exposed to the browser. Connections are per-user and scoped to the authenticated session.
HTTPS enforced at the ALB with TLS 1.2+; HTTP is not exposed. CSRF protection via SameSite cookie policy and origin validation. All user-controlled inputs are validated server-side before DB writes. Salesforce and form submission endpoints apply rate limiting. Public form endpoints (/f/, /api/submissions) are separated from authenticated endpoints in middleware to minimise attack surface. Dependency updates are reviewed before deployment; Docker base images use node:20-alpine (minimal attack surface).
PDF generation uses Puppeteer with a server-installed Chromium binary plus pdf-lib for post-processing. All rendering happens inside the ECS container in ap-southeast-2. Generated documents are stored in the workspace S3 bucket (encrypted at rest). E-signature envelopes track recipient status in the database; signing tokens are single-use and time-limited. No document content is sent to external rendering APIs or third-party cloud services.
All services — ECS cluster, Aurora cluster, S3 buckets, SES sending, Secrets Manager, and ALB — are provisioned exclusively in AWS ap-southeast-2 (Sydney). No cross-region replication is configured. Backups created by Aurora automated backup also remain in ap-southeast-2. This design satisfies Australian data residency requirements relevant to NDIS and Aged Care providers under the Privacy Act 1988 and relevant NDIS Practice Standards.
All public API routes live under /api/v1/ and are authenticated with Bearer tokens (Authorization: Bearer <key>). Keys are generated with a cryptographically random 60-character payload and a scope prefix (mk_live_ for read-write, mk_read_ for read-only). Only a SHA-256 hash of the raw key is stored — the plain-text key is shown once at creation and is unrecoverable thereafter. Per-request auth looks up the hash in the api_keys table, checks the revokedAt and expiresAt fields, and updates lastUsedAt non-blocking. CORS headers are returned on all /api/v1/* routes so browser-based integrations work. Responses use cursor-based pagination with base64-encoded ISO timestamps to avoid offset drift on live data. The middleware layer passes /api/v1/* through without touching the NextAuth session cookie stack, keeping the two auth paths fully independent.
Webhook endpoints are registered per workspace with a URL, a signing secret (minimum 32 characters), and a set of subscribed event types. When an event fires, the server serialises the payload as JSON, computes an HMAC-SHA256 signature over the raw bytes using the endpoint's secret, and attaches it as the X-Maica-Signature: sha256=<hex> header — allowing the receiving server to verify authenticity without a shared session. Delivery attempts time out after 10 seconds; the outcome (delivered / failed) and HTTP status code are recorded against the endpoint alongside lastDeliveryAt and a running failureCount. Signing secrets are stored server-side only and are never exposed in API responses after creation. A test delivery endpoint (POST /api/v1/webhooks/{id}/test) sends a synthetic test.ping event so integrators can verify their endpoint configuration before going live.