Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
af60925
fix(code-quality): address AI findings from issue #91 (#92)
sarah-artificerinnovations May 12, 2026
af32bdb
feat: CalVer template releases with git-cliff changelog (issue #82) (…
mei-artificerinnovations May 12, 2026
5eaf8f2
fix(ci): handle PR base-branch retargeting via pull_request edited ev…
sarah-artificerinnovations May 13, 2026
3f41f1a
Optional label bridge: sync org GitHub Project Status from project/st…
ZappoMan May 13, 2026
bbef2e6
feat(preview): CloudFront signed-cookie access control (issue #80) (#90)
diego-artificerinnovations May 13, 2026
fc1d2e0
fix(ci): avoid secrets in workflow if expressions (#107) (#108)
ZappoMan May 13, 2026
ffe6d33
fix: dark mode for auth, billing, dashboard, and profile components (…
rahul-artificerinnovations May 13, 2026
6526250
feat(ci): per-component status table in PR preview comment (#85) (#110)
sarah-artificerinnovations May 13, 2026
1056928
feat(quality): enforce pre-commit hooks with lint-staged (#99) (#111)
diego-artificerinnovations May 13, 2026
9580fa4
fix(dark-mode): add dark variants to ProtectedRoute loading state (#109)
rahul-artificerinnovations May 13, 2026
7c6951a
feat(landing): add marketing/SEO feature rows and reorder grid for B2…
ZappoMan May 13, 2026
a3d69a4
feat(ci): Lighthouse CI for PR preview environments (#96) (#112)
mei-artificerinnovations May 13, 2026
18e51fe
refactor: Remove DebugTools component from web and mobile apps (#150)
mei-artificerinnovations May 13, 2026
a8d2cd8
fix(ci): fix GitHub Deployment visibility for PR previews (#140) (#149)
sarah-artificerinnovations May 13, 2026
e2b4187
fix(web): decorative nav logo alt for a11y (#145) (#151)
ZappoMan May 13, 2026
c04cf71
fix(seo): fix robots.txt returning HTML on PR preview domain (#142) (…
sarah-artificerinnovations May 13, 2026
d9f2452
feat(infra): add CSP report-only header via custom CloudFront policy …
mei-artificerinnovations May 13, 2026
d91f986
fix(cdn): HTTP/2+3 for all CloudFront distributions and cache headers…
sarah-artificerinnovations May 13, 2026
42e1876
perf: code splitting, CLS fix, self-hosted placeholders (#146 A+B+C) …
mei-artificerinnovations May 13, 2026
d357ecd
fix: do not cancel CI on PR title/body edits (#162)
sarah-artificerinnovations May 13, 2026
3508dd6
Refresh landing page marketing imagery (#160)
ZappoMan May 14, 2026
2aa00d0
feat(billing): static marketing pricing table (issue #163) (#164)
mei-artificerinnovations May 14, 2026
e7f3c2c
feat(web): update SEO hero image (#185)
rahul-artificerinnovations May 14, 2026
5083672
fix: prevent white screen after login (#164) (#184)
sarah-artificerinnovations May 14, 2026
91c85e9
feat: redesign /dashboard as annotated sample-app showcase (#174)
sarah-artificerinnovations May 14, 2026
f060848
fix(csp): allow Supabase Storage origins in img-src (#183) (#186)
diego-artificerinnovations May 14, 2026
94cea21
feat(web): prerender-home with renderToStaticMarkup; unconditional cr…
mei-artificerinnovations May 14, 2026
6c9b3a0
fix: align dashboard content width with header/footer (#193)
sarah-artificerinnovations May 14, 2026
526cc11
feat(web): lazy-load below-fold landing sections (#175 PR 2/3) (#181)
mei-artificerinnovations May 14, 2026
898e32a
feat(web): AuthShell composition wrapper, lazy-loaded; drop hydrateRo…
mei-artificerinnovations May 14, 2026
57a8d8c
fix: block all Summarize buttons while any summarize RPC is in flight…
sarah-artificerinnovations May 14, 2026
177b3e2
feat(web): crossfade carousel in landing hero (issue #194) (#200)
diego-artificerinnovations May 14, 2026
5e8d6ad
perf(billing): hoist plan fetch into BillingProvider context (#203)
sarah-artificerinnovations May 14, 2026
7194829
test(web): add AuthShell render test; remove coverage exclusion (#202)
mei-artificerinnovations May 14, 2026
f28e042
refactor(web): extract shared layout class constants (#195) (#201)
mei-artificerinnovations May 14, 2026
9cc4a6f
test(billing): pgTAP regression for billing_record_usage_event idempo…
sarah-artificerinnovations May 14, 2026
20d2ad6
test(web): dashboard component test coverage + lift coverage gates (#…
sarah-artificerinnovations May 15, 2026
aedf3c3
fix(web): true image crossfade in hero carousel (issue #207) (#211)
diego-artificerinnovations May 15, 2026
6d09f1a
fix(web): share critical theme CSS for FOUC (inline + bundle) (#213)
ZappoMan May 15, 2026
b957b2b
feat(web): PublicShell + lazy auth; marketing session hint; policy/he…
ZappoMan May 15, 2026
7fd3ffa
fix mobile build (#217)
ZappoMan May 16, 2026
b2a7f82
feat(mobile): web-parity billing dashboard and billing fixes (#218)
ZappoMan May 16, 2026
74a24c0
feat(web): render AnnotatedPrimitive tooltip as visible inline text (…
sarah-artificerinnovations May 16, 2026
459b70a
feat(mobile): read-only billing UI and shared presentation package (#…
ZappoMan May 16, 2026
f70cbe3
fix(web): scroll to top on route navigation (#222)
mei-artificerinnovations May 16, 2026
b053560
fix(web): standardize public header — delegate PolicyPublicHeader to …
diego-artificerinnovations May 16, 2026
bd9e611
fix(web): landing and app UI polish — images, layout, nav, and brandi…
ZappoMan May 16, 2026
fb1e5eb
docs: remove stale task lists and billing review artifacts
ZappoMan May 16, 2026
44c4b0a
Revert "docs: remove stale task lists and billing review artifacts"
ZappoMan May 16, 2026
09b00bd
docs: remove stale task lists and billing review artifacts (#225)
ZappoMan May 16, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ module.exports = {
},
plugins: ['@typescript-eslint'],
rules: {
'@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
// varsIgnorePattern covers _prefixed destructured variables (e.g. const { _unused, ...rest } = obj)
'@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_', varsIgnorePattern: '^_' }],
'@typescript-eslint/no-explicit-any': 'warn',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
Expand Down
32 changes: 32 additions & 0 deletions .github/workflows/check-csp-hash.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: Check CSP Hash

on:
push:
branches:
- main
- develop
paths:
- 'apps/web/index.html'
- 'infra/aws/pr-preview-stack.yml'
- 'scripts/check-csp-hash.mjs'
pull_request:
paths:
- 'apps/web/index.html'
- 'infra/aws/pr-preview-stack.yml'
- 'scripts/check-csp-hash.mjs'
- '.github/workflows/check-csp-hash.yml'

permissions:
contents: read

jobs:
check-csp-hash:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20.x
- name: Verify CSP inline-script hash
run: node scripts/check-csp-hash.mjs
4 changes: 2 additions & 2 deletions .github/workflows/check-merge-strategy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ name: Check Merge Strategy

on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
types: [opened, synchronize, reopened, ready_for_review, edited]

permissions:
pull-requests: write
issues: write

jobs:
check-merge-strategy:
if: github.base_ref == 'main'
if: github.base_ref == 'main' && (github.event.action != 'edited' || github.event.changes.base)
runs-on: ubuntu-latest
steps:
- name: Add merge strategy reminder comment
Expand Down
89 changes: 89 additions & 0 deletions .github/workflows/deploy-staging.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ on:
permissions:
contents: read
id-token: write
deployments: write

concurrency:
group: staging-deploy
Expand Down Expand Up @@ -146,6 +147,94 @@ jobs:
--environment staging \
--region "${AWS_REGION_VALUE}"

- name: Generate staging signed cookie bootstrap URL
id: signed_cookies
shell: bash
env:
CLOUDFRONT_SIGNING_KEY: ${{ secrets.CLOUDFRONT_SIGNING_KEY }}
CLOUDFRONT_SIGNING_KEY_ID: ${{ secrets.CLOUDFRONT_SIGNING_KEY_ID }}
run: |
set -euo pipefail
# secrets.* is not allowed in step `if:` — gate here (direct URL access when neither secret is set).
if [[ -z "${CLOUDFRONT_SIGNING_KEY:-}" && -z "${CLOUDFRONT_SIGNING_KEY_ID:-}" ]]; then
exit 0
fi
if [[ -z "${CLOUDFRONT_SIGNING_KEY:-}" || -z "${CLOUDFRONT_SIGNING_KEY_ID:-}" ]]; then
echo "::error::CLOUDFRONT_SIGNING_KEY and CLOUDFRONT_SIGNING_KEY_ID must both be set. Configure both secrets or neither."
exit 1
fi
STAGING_DOMAIN="staging.${DOMAIN}"
RESOURCE="https://${STAGING_DOMAIN}/*"
EXPIRY=$(date -u -d "+30 days" +%s)

POLICY_JSON=$(printf '{"Statement":[{"Resource":"%s","Condition":{"DateLessThan":{"AWS:EpochTime":%s}}}]}' \
"${RESOURCE}" "${EXPIRY}")

# CloudFront URL-safe base64: + → -, / → ~, = → _
CF_POLICY=$(printf '%s' "${POLICY_JSON}" | base64 -w0 | tr '+' '-' | tr '/' '~' | tr '=' '_')

# Sign with RSA-SHA1 (CloudFront signed cookies requirement)
KEY_FILE=$(mktemp); chmod 600 "${KEY_FILE}"
printf '%s' "${CLOUDFRONT_SIGNING_KEY}" > "${KEY_FILE}"
CF_SIGNATURE=$(printf '%s' "${POLICY_JSON}" | \
openssl dgst -sha1 -sign "${KEY_FILE}" | base64 -w0 | tr '+' '-' | tr '/' '~' | tr '=' '_')
rm -f "${KEY_FILE}"

BOOTSTRAP_URL="https://${STAGING_DOMAIN}/_preview-auth?policy=${CF_POLICY}&sig=${CF_SIGNATURE}&kid=${CLOUDFRONT_SIGNING_KEY_ID}&dest=/"
echo "BOOTSTRAP_URL=${BOOTSTRAP_URL}" >> "${GITHUB_OUTPUT}"
echo "STAGING_URL=https://${STAGING_DOMAIN}" >> "${GITHUB_OUTPUT}"

- name: Create GitHub Deployment (staging)
uses: actions/github-script@v7
env:
BOOTSTRAP_URL: ${{ steps.signed_cookies.outputs.BOOTSTRAP_URL }}
STAGING_URL: ${{ steps.signed_cookies.outputs.STAGING_URL || format('https://staging.{0}', env.DOMAIN) }}
with:
script: |
const environmentUrl = process.env.BOOTSTRAP_URL || process.env.STAGING_URL;
const deployment = await github.rest.repos.createDeployment({
owner: context.repo.owner,
repo: context.repo.repo,
ref: context.sha,
environment: 'staging',
auto_merge: false,
required_contexts: [],
description: 'Staging deployment',
});
if (deployment.data.id) {
await github.rest.repos.createDeploymentStatus({
owner: context.repo.owner,
repo: context.repo.repo,
deployment_id: deployment.data.id,
state: 'success',
environment_url: environmentUrl,
description: 'Staging deployed',
});
}

- name: Write Actions run summary
shell: bash
env:
BOOTSTRAP_URL: ${{ steps.signed_cookies.outputs.BOOTSTRAP_URL }}
STAGING_URL: ${{ steps.signed_cookies.outputs.STAGING_URL || format('https://staging.{0}', env.DOMAIN) }}
run: |
set -euo pipefail
if [[ -n "${BOOTSTRAP_URL}" ]]; then
cat >> "${GITHUB_STEP_SUMMARY}" <<SUMMARY
## Staging Deployment

**Access link (signed cookies):** ${BOOTSTRAP_URL}

> Click the link to set your access cookie, then browse staging normally. Expires in 30 days.
SUMMARY
else
cat >> "${GITHUB_STEP_SUMMARY}" <<SUMMARY
## Staging Deployment

**Staging URL:** ${STAGING_URL}
SUMMARY
fi

deploy-mobile-staging:
if: vars.MOBILE_ENABLED != 'false'
needs: [deploy-staging]
Expand Down
Loading
Loading