Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
cbbf5da
docs: add iOS app design
lan17 May 10, 2026
3b68584
feat: add iOS-ready API providers
lan17 May 10, 2026
d475e14
feat: add API runtime bootstrap
lan17 May 10, 2026
976dc64
feat: add native iOS setup flow
lan17 May 10, 2026
aa3c5b8
feat: add Capacitor iOS scaffold
lan17 May 11, 2026
f2287d6
feat: add iOS native runtime detection
lan17 May 11, 2026
96e30f7
fix: harden iOS native setup flow
lan17 May 11, 2026
c62256a
feat: persist iOS auth in Keychain
lan17 Jun 14, 2026
a08684a
feat: handle iOS app lifecycle media
lan17 Jun 14, 2026
dc68b2a
fix: close iOS media lifecycle races
lan17 Jun 14, 2026
153a30b
fix: ignore stale iOS preview activations
lan17 Jun 14, 2026
4dc8e2c
fix: serialize iOS preview stops
lan17 Jun 14, 2026
f5a5b2f
feat: add iOS deep link routing
lan17 Jun 14, 2026
d567897
fix: harden iOS deep link routing
lan17 Jun 14, 2026
02c0d62
fix: harden iOS safe-area layout
lan17 Jun 14, 2026
2529cdf
fix: close iOS safe-area review gaps
lan17 Jun 14, 2026
49501f7
test: expand iOS layout e2e coverage
lan17 Jun 14, 2026
05991bc
fix: harden iOS live preview playback
lan17 Jun 14, 2026
cbf04a7
fix: release failed iOS live preview media
lan17 Jun 14, 2026
8611d0e
fix: release live preview on stop failures
lan17 Jun 14, 2026
ce56f51
fix: stop stale background preview activations
lan17 Jun 14, 2026
2bae505
fix: clear stale preview recovery errors
lan17 Jun 14, 2026
391c8b8
fix: clean stale preview activation after stop
lan17 Jun 14, 2026
1aeaf3d
fix: surface live preview cleanup failures
lan17 Jun 14, 2026
423eb6e
fix: ignore stale preview renewal failures
lan17 Jun 14, 2026
a95e191
fix: guard stale preview start errors
lan17 Jun 14, 2026
ffc70a0
fix: clean stale preview renewals
lan17 Jun 14, 2026
a714f86
fix: harden notification event detail UX
lan17 Jun 14, 2026
10215d0
feat: add mobile device registry
lan17 Jun 14, 2026
63be5d2
feat: add mobile device API routes
lan17 Jun 14, 2026
2b88e3f
feat: add iOS APNs registration
lan17 Jun 14, 2026
4b3d810
feat: add APNs mobile notifier
lan17 Jun 14, 2026
90f002d
feat: route iOS notification taps
lan17 Jun 14, 2026
8e9ed88
fix: keep iOS SPM manifest on Swift tools 6.2
lan17 Jun 14, 2026
a38998e
docs: add iOS personal build runbook
lan17 Jun 14, 2026
dccfc32
fix: harden iOS mobile integration
lan17 Jun 14, 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
45 changes: 45 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,54 @@ jobs:
- name: UI check
run: pnpm --dir ui check

- name: Install Playwright browsers
run: pnpm --dir ui exec playwright install --with-deps chromium webkit

- name: UI e2e
run: pnpm --dir ui test:e2e

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: coverage.xml
fail_ci_if_error: false

ios-native:
runs-on: macos-26

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 10.15.1
run_install: false

- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: "22.12.0"
cache: pnpm
cache-dependency-path: ui/pnpm-lock.yaml

- name: Install UI dependencies
run: pnpm --dir ui install --frozen-lockfile

- name: Sync Capacitor iOS project
run: pnpm --dir ui ios:sync

- name: Verify committed iOS sync output
run: git diff --exit-code -- ui/ios ui/capacitor.config.ts ui/package.json ui/pnpm-lock.yaml

- name: Build iOS simulator app
run: |
xcodebuild \
-project ui/ios/App/App.xcodeproj \
-scheme App \
-destination 'generic/platform=iOS Simulator' \
-configuration Debug \
CODE_SIGNING_ALLOWED=NO \
build
77 changes: 77 additions & 0 deletions alembic/versions/7b0b1fbfc69b_add_mobile_device_registry.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
"""add mobile device registry

Revision ID: 7b0b1fbfc69b
Revises: d936851f725a
Create Date: 2026-06-14 00:00:00.000000

"""

from collections.abc import Sequence

import sqlalchemy as sa
from alembic import op
from sqlalchemy.dialects import postgresql

# revision identifiers, used by Alembic.
revision: str = "7b0b1fbfc69b"
down_revision: str | None = "d936851f725a"
branch_labels: str | Sequence[str] | None = None
depends_on: str | Sequence[str] | None = None


def upgrade() -> None:
op.create_table(
"mobile_devices",
sa.Column("id", sa.Text(), nullable=False),
sa.Column("platform", sa.Text(), nullable=False),
sa.Column("apns_token_hash", sa.Text(), nullable=False),
sa.Column("apns_token", sa.Text(), nullable=False),
sa.Column("apns_environment", sa.Text(), nullable=False),
sa.Column("bundle_id", sa.Text(), nullable=False),
sa.Column("device_name", sa.Text(), nullable=True),
sa.Column("app_version", sa.Text(), nullable=True),
sa.Column(
"capabilities",
postgresql.JSONB(astext_type=sa.Text()),
server_default=sa.text("'{}'::jsonb"),
nullable=False,
),
sa.Column("enabled", sa.Boolean(), server_default=sa.text("true"), nullable=False),
sa.Column(
"created_at",
sa.DateTime(timezone=True),
server_default=sa.text("now()"),
nullable=False,
),
sa.Column(
"updated_at",
sa.DateTime(timezone=True),
server_default=sa.text("now()"),
nullable=False,
),
sa.Column("last_seen_at", sa.DateTime(timezone=True), nullable=True),
sa.Column("last_push_at", sa.DateTime(timezone=True), nullable=True),
sa.Column("last_push_error", sa.Text(), nullable=True),
sa.PrimaryKeyConstraint("id"),
sa.UniqueConstraint("apns_token_hash", name="uq_mobile_devices_apns_token_hash"),
)
op.create_index("idx_mobile_devices_enabled", "mobile_devices", ["enabled"], unique=False)
op.create_index(
"idx_mobile_devices_platform_environment",
"mobile_devices",
["platform", "apns_environment"],
unique=False,
)
op.create_index(
"idx_mobile_devices_updated_at_desc",
"mobile_devices",
[sa.literal_column("updated_at DESC")],
unique=False,
)


def downgrade() -> None:
op.drop_index("idx_mobile_devices_updated_at_desc", table_name="mobile_devices")
op.drop_index("idx_mobile_devices_platform_environment", table_name="mobile_devices")
op.drop_index("idx_mobile_devices_enabled", table_name="mobile_devices")
op.drop_table("mobile_devices")
Loading
Loading