Q/Documentation / v0.1Dashboard ↗
API / CLI / Agent workflow

Quick,
documented.

Publish a static directory, keep ownership and deployment history, and give Codex a safe operational workflow.

APIhttps://quick.mcamprodon.cat
Siteshttps://sites.mcamprodon.cat/field-notes/
01

Quickstart

Create a personal API key in the authenticated dashboard, configure the CLI and deploy a static directory.

quick init --api-url https://quick.mcamprodon.cat --token "quick_..."
quick doctor
quick deploy ./dist --site field-notes

The published site will be available at https://sites.mcamprodon.cat/field-notes/.

The API origin is derived automatically from VERCEL_PROJECT_PRODUCTION_URL.

02

Authentication

The web application uses Google OAuth through Better Auth. By default, new accounts and existing sessions must use an exact domain from AUTH_ALLOWED_DOMAINS. Set AUTH_ALLOWED_EMAILS to restrict access to a comma-separated list of exact addresses instead.

Web requests

Use the Better Auth session cookie created by Google sign-in.

CLI requests

Use a personal, revocable API key in the Bearer header.

Authorization: Bearer quick_...

# Environment variables override ~/.quick/config.json
QUICK_API_URL=https://quick.mcamprodon.cat
QUICK_API_TOKEN=quick_...

# Server-side authentication policy
AUTH_ALLOWED_DOMAINS=ara.cat
AUTH_ALLOWED_EMAILS=alice@ara.cat,bob@ara.cat

Never use Google OAuth tokens or browser cookies in the CLI. Create and rotate API keys from the dashboard.

Production database

Quick falls back to SQLite locally. Set DATABASE_URL to use any PostgreSQL-compatible service in production, including Neon, and run the migrations before serving traffic.

DATABASE_URL=postgresql://user:password@host/database?sslmode=require
DATABASE_POOL_MAX=5

npm run auth:migrate

Prefer a pooled PostgreSQL connection string in serverless environments. DATABASE_URL takes precedence over AUTH_DATABASE_PATH; migration from existing SQLite data is not automatic.

03

CLI reference

quick init --api-url <url> --token <key>Store API configuration in ~/.quick/config.json.
quick --json doctorVerify configuration, authentication and S3 reachability.
quick --json deploy ./dist --site <slug> --dry-runInventory and validate without publishing.
quick --json deploy ./dist --site <slug>Upload and publish the directory.
quick --json deployments get <slug>Read the current manifest.
quick --json request get /api/sitesUse the authenticated read-only escape hatch.

With --json, successful commands return {"ok":true,...}. Errors use {"ok":false,"error":{"code","message"}} and a non-zero exit code.

04

HTTP API

GET/api/healthCheck authentication, configuration and S3 reachability.
POST/api/deploymentsReserve a site and create presigned upload URLs.
POST/api/deployments/:id/completeValidate uploaded objects and publish the manifest.
GET/api/sitesList sites owned by the authenticated user.
GET/api/sites/:siteRead the currently published deployment manifest.
GET/api/sites/:site/deploymentsRead deployment history for a site.
DELETE/api/sites/:siteDelete the S3 prefix, site and deployment history.

Create an upload plan

POST https://quick.mcamprodon.cat/api/deployments
Authorization: Bearer quick_...
Content-Type: application/json

{
  "site": "field-notes",
  "files": [{
    "path": "index.html",
    "size": 1532,
    "contentType": "text/html",
    "sha256": "<64 lowercase hex characters>"
  }]
}

The response contains a deployment ID, one presigned S3 PUT URL per file, required headers and a relative completeUrl. Upload bytes directly to S3, then submit the same manifest to the completion endpoint.

Error codes

401 unauthorizedMissing or invalid session/API key.
409 site_ownedThe slug belongs to another user.
409 deployment_in_progressThe site already has a pending upload.
409 manifest_mismatchThe completion body differs from the upload plan.
413 file_limitToo many files or a file exceeds the configured size.
05

Codex skill

The companion skill teaches Codex to verify configuration, run a dry-run first, deploy only when requested and avoid exposing credentials or signed URLs.

Install from this repository

mkdir -p ~/.codex/skills
ln -s /absolute/path/to/quick/skills/quick-deploy \
  ~/.codex/skills/quick-deploy

Restart Codex after installation. Invoke it explicitly with:

$quick-deploy publish ./dist as field-notes
Safety

Runs doctor and --dry-run before unfamiliar deployments.

Ownership

Treats site_owned as a slug conflict, never as something to bypass.

Credentials

Uses personal API keys and never prints config, OAuth tokens or presigned URLs.

06

AWS infrastructure

This setup keeps S3 private, lets Quick upload through presigned URLs, and serves sites through CloudFront. Viewer access is an infrastructure decision: the distribution can be public or protected independently of Quick.

01Quick app02S3 / sites/*03CloudFront + OAC

1. Create the S3 bucket

  1. Create quick-artifacts-mcamprodon in eu-central-1.
  2. Keep Block Public Access enabled and Object Ownership set to Bucket owner enforced.
  3. Do not enable S3 static website hosting. CloudFront must use the regular S3 bucket endpoint.
  4. Quick stores objects under sites/<site-slug>/. The CLI uploads to presigned URLs, so bucket CORS is not required for this flow.

2. Give Quick access to the bucket

Attach this identity policy to the IAM user or role used by the Next.js application. Keep the resource restricted to the bucket and the sites/* prefix.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "InspectQuickBucket",
      "Effect": "Allow",
      "Action": "s3:ListBucket",
      "Resource": "arn:aws:s3:::quick-artifacts-mcamprodon"
    },
    {
      "Sid": "ManageQuickSites",
      "Effect": "Allow",
      "Action": ["s3:GetObject", "s3:PutObject", "s3:DeleteObject"],
      "Resource": "arn:aws:s3:::quick-artifacts-mcamprodon/sites/*"
    }
  ]
}

3. Create CloudFront with Origin Access Control

  1. Create a distribution with the S3 origin quick-artifacts-mcamprodon.s3.eu-central-1.amazonaws.com.
  2. Set the origin path to /sites. A viewer request for /demo/ will then read sites/demo/index.html from S3.
  3. Create an Origin Access Control for S3, select Sign requests, and use SigV4. Attach it to the origin.
  4. Use Redirect HTTP to HTTPS, allow GET/HEAD, and start with the managed CachingOptimized policy.

Add this bucket policy after replacing the account and distribution IDs:

{
  "Version": "2012-10-17",
  "Statement": [{
    "Sid": "AllowCloudFrontOACRead",
    "Effect": "Allow",
    "Principal": { "Service": "cloudfront.amazonaws.com" },
    "Action": "s3:GetObject",
    "Resource": "arn:aws:s3:::quick-artifacts-mcamprodon/sites/*",
    "Condition": {
      "StringEquals": {
        "AWS:SourceArn": "arn:aws:cloudfront::<AWS_ACCOUNT_ID>:distribution/<DISTRIBUTION_ID>"
      }
    }
  }]
}

4. Configure the sites hostname

  1. Request or import an ACM certificate in us-east-1 for the sites hostname, for example https://sites.mcamprodon.cat.
  2. Add that hostname as an alternate domain name on the distribution and select the certificate.
  3. Create a Route 53 alias A/AAAA record, or a CNAME with another DNS provider, pointing to CloudFront.
  4. The Quick application can use a separate hostname such as https://quick.mcamprodon.cat; it does not need to share cookies or authentication with the sites hostname.

5. Add the viewer-request Function

Create a CloudFront Function using JavaScript runtime 2.0. Copy infrastructure/cloudfront/viewer-request.js, publish it, and associate it with Viewer request on the sites behavior.

function handler(event) {
  var request = event.request;
  if (request.uri.endsWith("/")) request.uri += "index.html";
  else if (!request.uri.includes(".")) request.uri += "/index.html";
  return request;
}

This Function only rewrites directory-like URLs to index.html. It does not implement authentication or authorization.

6. Configure Quick

BETTER_AUTH_URL=https://quick.mcamprodon.cat
QUICK_PUBLIC_BASE_URL=https://sites.mcamprodon.cat

Quick uses QUICK_PUBLIC_BASE_URL to build links shown by the API, CLI and dashboard. It does not assume whether those URLs are public or protected.

Access policy

Public sites

Leave viewer access unrestricted and let CloudFront serve the static artifacts directly.

Restricted sites

Add the access mechanism required by your organization at CloudFront, a proxy, VPN or another gateway. Quick remains unchanged.

Verification checklist

Direct S3 URLReturns AccessDenied.
CloudFront site URLServes the deployed artifact according to the distribution access policy.
Nested routeRewrites to the corresponding index.html.
Quick dashboardOpens the configured public URL directly.

AWS references: S3 origins and OAC, CloudFront Functions, and alternate domain names.

07

Current constraints

  • Static files only; conventional sites should include index.html.
  • Site slugs are globally unique and owned by their first authenticated publisher.
  • Only one deployment can be pending per site.
  • Deployments overwrite matching paths but do not delete stale unmatched files.
  • SQLite is available for local development; production deployments should configure PostgreSQL with DATABASE_URL.
  • The bucket or CDN must serve objects under sites/<site>/.
  • Quick does not control viewer access to published sites; configure public or restricted access in the chosen CDN or hosting layer.