diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000..c7a2d1c5 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,101 @@ +## ๐Ÿ“‹ Description + + + + +--- + +## ๐ŸŽฏ Type of Change + + + +- [ ] ๐Ÿ› **Bug fix** (non-breaking change that fixes an issue) +- [ ] โœจ **Feature** (non-breaking change that adds functionality) +- [ ] ๐Ÿ“ **Documentation** (changes to docs, comments, or README) +- [ ] ๐Ÿ”ง **Refactor** (code change that doesn't affect functionality) +- [ ] โšก **Performance** (improvement in performance or optimization) +- [ ] ๐Ÿ” **Security** (security fix or improvement) +- [ ] ๐ŸŽจ **Style** (formatting, linting, or minor code style changes) +- [ ] ๐Ÿ—๏ธ **Architecture** (significant structural changes) + +--- + +## ๐Ÿ“ฆ Affected Areas + + + +- [ ] ๐Ÿ“ฑ **Mobile** (Flutter - Client/Worker app) +- [ ] ๐ŸŒ **Web** (React Dashboard) +- [ ] ๐Ÿ”Œ **Backend** (APIs, Data Connect, Cloud Functions) +- [ ] ๐Ÿ—„๏ธ **Database** (Schema changes, migrations) +- [ ] ๐Ÿš€ **CI/CD** (GitHub Actions, deployment configs) +- [ ] ๐Ÿ“š **Documentation** (Docs, onboarding guides) + +--- + +## ๐Ÿ”— Related Issues + + + +Closes # +Related to # + +--- + +## โœ… Testing + + + +**Test Details:** + + + +--- + +## ๐Ÿ”„ Breaking Changes + + + +- [ ] No breaking changes +- [ ] Yes, breaking changes: + +**Details:** + + + +--- + +## ๐ŸŽฏ Checklist + + + +- [ ] Code follows project style guidelines +- [ ] Self-review completed +- [ ] Comments added for complex logic +- [ ] Documentation updated (if applicable) +- [ ] No new console warnings/errors +- [ ] Tests pass locally +- [ ] Branch is up-to-date with `dev` +- [ ] Commit messages are clear and descriptive +- [ ] Sensitive data is not committed +- [ ] Environment variables documented (if added) + +--- + +## ๐Ÿ“ Additional Notes + + + + +--- + +## ๐Ÿ” Review Checklist for Maintainers + +- [ ] Code quality and readability +- [ ] Design patterns follow project conventions +- [ ] Test coverage is adequate +- [ ] Performance implications reviewed +- [ ] Security concerns addressed +- [ ] Documentation is complete +- [ ] Breaking changes properly communicated +- [ ] Cross-platform compatibility (if applicable) diff --git a/.github/scripts/attach-apk-to-release.sh b/.github/scripts/attach-apk-to-release.sh new file mode 100755 index 00000000..4491178f --- /dev/null +++ b/.github/scripts/attach-apk-to-release.sh @@ -0,0 +1,60 @@ +#!/bin/bash + +# ============================================================================= +# Attach APK to GitHub Release +# ============================================================================= +# This script attaches a built APK to a GitHub Release with proper naming +# +# Usage: +# ./attach-apk-to-release.sh +# +# Arguments: +# tag_name - Git tag name (e.g., krow-withus-worker-mobile/dev-v0.1.0) +# app - worker-mobile-app or client-mobile-app +# app_name - staff or client (internal build folder name) +# version - Version number (e.g., 0.1.0) +# environment - dev, stage, or prod +# +# Environment Variables: +# GH_TOKEN - GitHub token for gh CLI authentication +# ============================================================================= + +set -e + +TAG_NAME="$1" +APP="$2" +APP_NAME="$3" +VERSION="$4" +ENV="$5" + +if [ -z "$TAG_NAME" ] || [ -z "$APP" ] || [ -z "$APP_NAME" ] || [ -z "$VERSION" ] || [ -z "$ENV" ]; then + echo "โŒ Error: Missing required arguments" >&2 + echo "Usage: $0 " >&2 + exit 1 +fi + +# Find APK in build output +APK_PATH="apps/mobile/apps/${APP_NAME}/build/app/outputs/flutter-apk/app-release.apk" + +if [ ! -f "$APK_PATH" ]; then + echo "โŒ Error: APK not found at $APK_PATH" >&2 + echo "Searching for APK files..." >&2 + find apps/mobile/apps/${APP_NAME} -name "*.apk" + exit 1 +fi + +# Create proper APK name based on app type +if [ "$APP" = "worker-mobile-app" ]; then + APK_NAME="krow-withus-worker-mobile-${ENV}-v${VERSION}.apk" +else + APK_NAME="krow-withus-client-mobile-${ENV}-v${VERSION}.apk" +fi + +# Copy APK with proper name +cp "$APK_PATH" "/tmp/$APK_NAME" + +# Upload to GitHub Release +echo "๐Ÿ“ค Uploading $APK_NAME to release $TAG_NAME..." >&2 +gh release upload "$TAG_NAME" "/tmp/$APK_NAME" --clobber + +echo "โœ… APK attached to release: $APK_NAME" >&2 diff --git a/.github/scripts/create-release-summary.sh b/.github/scripts/create-release-summary.sh new file mode 100755 index 00000000..ddefb1d9 --- /dev/null +++ b/.github/scripts/create-release-summary.sh @@ -0,0 +1,73 @@ +#!/bin/bash +# Generate release summary for GitHub Actions +# Usage: ./create-release-summary.sh + +set -e + +APP=$1 +ENV=$2 +VERSION=$3 +TAG_NAME=$4 + +if [ -z "$APP" ] || [ -z "$ENV" ] || [ -z "$VERSION" ] || [ -z "$TAG_NAME" ]; then + echo "โŒ Error: Missing required parameters" + echo "Usage: ./create-release-summary.sh " + exit 1 +fi + +# Determine display names +if [ "$APP" = "worker-mobile-app" ]; then + APP_DISPLAY="Worker Product" + APP_EMOJI="๐Ÿ‘ท" +else + APP_DISPLAY="Client Product" + APP_EMOJI="๐Ÿ’ผ" +fi + +ENV_UPPER=$(echo "$ENV" | tr '[:lower:]' '[:upper:]') +RELEASE_NAME="Krow With Us - ${APP_DISPLAY} - ${ENV_UPPER} - v${VERSION}" + +# Environment emoji +case "$ENV" in + dev) + ENV_EMOJI="๐Ÿ”ง" + ;; + stage) + ENV_EMOJI="๐ŸŽญ" + ;; + prod) + ENV_EMOJI="๐Ÿš€" + ;; + *) + ENV_EMOJI="๐Ÿ“ฆ" + ;; +esac + +# Generate summary +cat << EOF >> $GITHUB_STEP_SUMMARY +## ๐ŸŽ‰ Release Created Successfully + +### ${APP_EMOJI} Application Details +- **App:** ${APP_DISPLAY} +- **Environment:** ${ENV_EMOJI} ${ENV_UPPER} +- **Version:** \`${VERSION}\` +- **Tag:** \`${TAG_NAME}\` + +### ๐Ÿ“ฆ Release Information +**Release Name:** ${RELEASE_NAME} + +### โœ… Next Steps + +1. ๐Ÿ” **Verify** the tag and release on GitHub +2. ๐Ÿ—๏ธ **Trigger** CodeMagic build (if configured) +3. ๐Ÿ“ฑ **Monitor** app store deployment +4. ๐Ÿ“š **Update** project documentation if needed +5. ๐ŸŽฏ **Communicate** release to stakeholders + +### ๐Ÿ”— Quick Links +- [View Tag](../../releases/tag/${TAG_NAME}) +- [Release Documentation](../../docs/release/MOBILE_RELEASE_PLAN.md) +- [CHANGELOG](../../apps/mobile/apps/${APP}/CHANGELOG.md) +EOF + +echo "โœ… Summary generated successfully" diff --git a/.github/scripts/extract-release-notes.sh b/.github/scripts/extract-release-notes.sh new file mode 100755 index 00000000..408d969f --- /dev/null +++ b/.github/scripts/extract-release-notes.sh @@ -0,0 +1,71 @@ +#!/bin/bash +# Extract release notes from CHANGELOG for a specific version +# Usage: ./extract-release-notes.sh + +set -e + +APP=$1 +VERSION=$2 +ENV=$3 +TAG_NAME=$4 +OUTPUT_FILE=$5 + +if [ -z "$APP" ] || [ -z "$VERSION" ] || [ -z "$ENV" ] || [ -z "$TAG_NAME" ] || [ -z "$OUTPUT_FILE" ]; then + echo "โŒ Error: Missing required parameters" >&2 + echo "Usage: ./extract-release-notes.sh " >&2 + exit 1 +fi + +# Determine CHANGELOG path and app name +if [ "$APP" = "worker-mobile-app" ]; then + CHANGELOG_PATH="apps/mobile/apps/staff/CHANGELOG.md" + APP_NAME="Staff Product (Worker)" +else + CHANGELOG_PATH="apps/mobile/apps/client/CHANGELOG.md" + APP_NAME="Client Product" +fi + +# Try to extract release notes for this version +if [ -f "$CHANGELOG_PATH" ]; then + echo "๐Ÿ“ Found CHANGELOG at $CHANGELOG_PATH" >&2 + + # Extract section for this version + # Look for ## [vVERSION] or ## [VERSION] and collect content until next ## [ header + # Try with 'v' prefix first (common format), then without + CHANGELOG_CONTENT=$(awk "/^## \[v${VERSION}\]/{flag=1; next} /^## \[/{flag=0} flag" "$CHANGELOG_PATH") + + # If still empty, try without 'v' prefix + if [ -z "$CHANGELOG_CONTENT" ]; then + CHANGELOG_CONTENT=$(awk "/^## \[${VERSION}\]/{flag=1; next} /^## \[/{flag=0} flag" "$CHANGELOG_PATH") + fi + + if [ -z "$CHANGELOG_CONTENT" ]; then + echo "โš ๏ธ Warning: No CHANGELOG entry found for version $VERSION" >&2 + NOTES="**Environment:** $ENV +**Tag:** $TAG_NAME + +## What is new in this release + +โš ๏ธ No CHANGELOG entry found for this version. Please update the CHANGELOG manually." + else + echo "โœ… Extracted release notes for version $VERSION" >&2 + NOTES="**Environment:** $ENV +**Tag:** $TAG_NAME + +## What is new in this release + +$CHANGELOG_CONTENT" + fi +else + echo "โš ๏ธ Warning: CHANGELOG not found at $CHANGELOG_PATH" >&2 + NOTES="**Environment:** $ENV +**Tag:** $TAG_NAME + +## What is new in this release + +โš ๏ธ CHANGELOG file not found at $CHANGELOG_PATH" +fi + +# Save to output file +echo "$NOTES" > "$OUTPUT_FILE" +echo "โœ… Release notes saved to $OUTPUT_FILE" >&2 diff --git a/.github/scripts/extract-version.sh b/.github/scripts/extract-version.sh new file mode 100755 index 00000000..51e5b031 --- /dev/null +++ b/.github/scripts/extract-version.sh @@ -0,0 +1,52 @@ +#!/bin/bash +# Extract version from version file for products +# Usage: ./extract-version.sh +# app: worker-mobile-app or client-mobile-app + +set -e + +APP=$1 + +if [ -z "$APP" ]; then + echo "โŒ Error: App parameter required (worker-mobile-app or client-mobile-app)" >&2 + exit 1 +fi + +# Determine pubspec path +if [ "$APP" = "worker-mobile-app" ]; then + PUBSPEC_PATH="apps/mobile/apps/staff/pubspec.yaml" + APP_NAME="Staff Product (Worker)" +else + PUBSPEC_PATH="apps/mobile/apps/client/pubspec.yaml" + APP_NAME="Client Product" +fi + +# Check if pubspec exists +if [ ! -f "$PUBSPEC_PATH" ]; then + echo "โŒ Error: pubspec.yaml not found at $PUBSPEC_PATH" >&2 + echo "๐Ÿ“ Current directory: $(pwd)" >&2 + echo "๐Ÿ“‚ Directory contents:" >&2 + ls -la apps/mobile/apps/ 2>&1 | head -20 >&2 + exit 1 +fi + +# Extract version (format: X.Y.Z+buildNumber or X.Y.Z-suffix) +VERSION_LINE=$(grep "^version:" "$PUBSPEC_PATH") +if [ -z "$VERSION_LINE" ]; then + echo "โŒ Error: Could not find version in $PUBSPEC_PATH" >&2 + exit 1 +fi + +# Extract full version including suffix/build number +VERSION=$(echo "$VERSION_LINE" | sed 's/version: *//' | tr -d ' ') + +# Validate version format (X.Y.Z with optional +build or -suffix) +# Use grep for better portability across different bash versions +if ! echo "$VERSION" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+(\+[a-zA-Z0-9]+|-[a-zA-Z0-9]+)?$'; then + echo "โŒ Error: Invalid version format in pubspec.yaml: $VERSION" >&2 + echo "Expected format: X.Y.Z, X.Y.Z+build, or X.Y.Z-suffix (e.g., 0.1.0, 0.1.0+12, 0.1.0-m3)" >&2 + exit 1 +fi + +echo "โœ… Extracted version from $PUBSPEC_PATH: $VERSION" >&2 +echo "$VERSION" diff --git a/.github/scripts/generate-tag-name.sh b/.github/scripts/generate-tag-name.sh new file mode 100755 index 00000000..8376a217 --- /dev/null +++ b/.github/scripts/generate-tag-name.sh @@ -0,0 +1,22 @@ +#!/bin/bash +# Generate tag name for product release +# Usage: ./generate-tag-name.sh + +set -e + +APP=$1 +ENV=$2 +VERSION=$3 + +if [ -z "$APP" ] || [ -z "$ENV" ] || [ -z "$VERSION" ]; then + echo "โŒ Error: Missing required parameters" >&2 + echo "Usage: ./generate-tag-name.sh " >&2 + exit 1 +fi + +# Strip -mobile-app suffix from app name for cleaner tag names +# worker-mobile-app -> worker, client-mobile-app -> client +APP_TAG=$(echo "$APP" | sed 's/-mobile-app$//') + +TAG_NAME="krow-withus-${APP_TAG}-mobile/${ENV}-v${VERSION}" +echo "$TAG_NAME" diff --git a/.github/scripts/setup-apk-signing.sh b/.github/scripts/setup-apk-signing.sh new file mode 100755 index 00000000..197df4eb --- /dev/null +++ b/.github/scripts/setup-apk-signing.sh @@ -0,0 +1,102 @@ +#!/bin/bash + +# ============================================================================= +# Setup APK Signing for GitHub Actions +# ============================================================================= +# This script configures Android APK signing by decoding keystores from +# GitHub Secrets and setting up environment variables for build.gradle.kts +# +# Usage: +# ./setup-apk-signing.sh +# +# Arguments: +# app - worker-mobile-app or client-mobile-app +# environment - dev, stage, or prod +# temp_dir - Temporary directory for keystore files (e.g., ${{ runner.temp }}) +# +# Environment Variables (must be set): +# WORKER_KEYSTORE_DEV_BASE64, WORKER_KEYSTORE_STAGING_BASE64, WORKER_KEYSTORE_PROD_BASE64 +# WORKER_KEYSTORE_PASSWORD_DEV, WORKER_KEYSTORE_PASSWORD_STAGING, WORKER_KEYSTORE_PASSWORD_PROD +# WORKER_KEY_ALIAS_DEV, WORKER_KEY_ALIAS_STAGING, WORKER_KEY_ALIAS_PROD +# WORKER_KEY_PASSWORD_DEV, WORKER_KEY_PASSWORD_STAGING, WORKER_KEY_PASSWORD_PROD +# CLIENT_KEYSTORE_DEV_BASE64, CLIENT_KEYSTORE_STAGING_BASE64, CLIENT_KEYSTORE_PROD_BASE64 +# CLIENT_KEYSTORE_PASSWORD_DEV, CLIENT_KEYSTORE_PASSWORD_STAGING, CLIENT_KEYSTORE_PASSWORD_PROD +# CLIENT_KEY_ALIAS_DEV, CLIENT_KEY_ALIAS_STAGING, CLIENT_KEY_ALIAS_PROD +# CLIENT_KEY_PASSWORD_DEV, CLIENT_KEY_PASSWORD_STAGING, CLIENT_KEY_PASSWORD_PROD +# ============================================================================= + +set -e + +APP="$1" +ENV="$2" +TEMP_DIR="$3" + +if [ -z "$APP" ] || [ -z "$ENV" ] || [ -z "$TEMP_DIR" ]; then + echo "โŒ Error: Missing required arguments" >&2 + echo "Usage: $0 " >&2 + exit 1 +fi + +echo "๐Ÿ” Setting up Android signing for $APP in $ENV environment..." >&2 + +# Determine which keystore to use +if [ "$APP" = "worker-mobile-app" ]; then + APP_TYPE="WORKER" + APP_NAME="STAFF" # CodeMagic uses STAFF in env var names +else + APP_TYPE="CLIENT" + APP_NAME="CLIENT" +fi + +# Convert environment to uppercase for env var names +ENV_UPPER=$(echo "$ENV" | tr '[:lower:]' '[:upper:]') +if [ "$ENV_UPPER" = "STAGE" ]; then + ENV_UPPER="STAGING" # CodeMagic uses STAGING instead of STAGE +fi + +# Get the keystore secret name dynamically +KEYSTORE_BASE64_VAR="${APP_TYPE}_KEYSTORE_${ENV_UPPER}_BASE64" +KEYSTORE_PASSWORD_VAR="${APP_TYPE}_KEYSTORE_PASSWORD_${ENV_UPPER}" +KEY_ALIAS_VAR="${APP_TYPE}_KEY_ALIAS_${ENV_UPPER}" +KEY_PASSWORD_VAR="${APP_TYPE}_KEY_PASSWORD_${ENV_UPPER}" + +# Get values using indirect expansion +KEYSTORE_BASE64="${!KEYSTORE_BASE64_VAR}" +KEYSTORE_PASSWORD="${!KEYSTORE_PASSWORD_VAR}" +KEY_ALIAS="${!KEY_ALIAS_VAR}" +KEY_PASSWORD="${!KEY_PASSWORD_VAR}" + +# Check if secrets are configured +if [ -z "$KEYSTORE_BASE64" ]; then + echo "โš ๏ธ WARNING: Keystore secret $KEYSTORE_BASE64_VAR is not configured!" >&2 + echo "โš ๏ธ APK will be built UNSIGNED for $ENV environment." >&2 + echo "โš ๏ธ Please configure GitHub Secrets as documented in docs/RELEASE/APK_SIGNING_SETUP.md" >&2 + exit 0 +fi + +# Create temporary directory for keystore +KEYSTORE_DIR="${TEMP_DIR}/keystores" +mkdir -p "$KEYSTORE_DIR" +KEYSTORE_PATH="$KEYSTORE_DIR/release.jks" + +# Decode keystore from base64 +echo "$KEYSTORE_BASE64" | base64 -d > "$KEYSTORE_PATH" + +if [ ! -f "$KEYSTORE_PATH" ]; then + echo "โŒ Failed to decode keystore!" >&2 + exit 1 +fi + +echo "โœ… Keystore decoded successfully" >&2 +echo "๐Ÿ“ฆ Keystore size: $(ls -lh "$KEYSTORE_PATH" | awk '{print $5}')" >&2 + +# Export environment variables for build.gradle.kts +# Using CodeMagic-compatible variable names +echo "CI=true" >> $GITHUB_ENV +echo "CM_KEYSTORE_PATH_${APP_NAME}=$KEYSTORE_PATH" >> $GITHUB_ENV +echo "CM_KEYSTORE_PASSWORD_${APP_NAME}=$KEYSTORE_PASSWORD" >> $GITHUB_ENV +echo "CM_KEY_ALIAS_${APP_NAME}=$KEY_ALIAS" >> $GITHUB_ENV +echo "CM_KEY_PASSWORD_${APP_NAME}=$KEY_PASSWORD" >> $GITHUB_ENV + +echo "โœ… Signing environment configured for $APP_NAME ($ENV environment)" >&2 +echo "๐Ÿ”‘ Using key alias: $KEY_ALIAS" >&2 diff --git a/.github/scripts/setup-mobile-github-secrets.sh b/.github/scripts/setup-mobile-github-secrets.sh new file mode 100755 index 00000000..3645bb82 --- /dev/null +++ b/.github/scripts/setup-mobile-github-secrets.sh @@ -0,0 +1,262 @@ +#!/bin/bash + +# ============================================================================= +# GitHub Secrets Setup Helper +# ============================================================================= +# This script helps you configure GitHub Secrets for APK signing +# +# Usage: +# ./setup-mobile-github-secrets.sh +# +# Reference: docs/RELEASE/APK_SIGNING_SETUP.md +# ============================================================================= + +set -e + +REPO_ROOT=$(git rev-parse --show-toplevel) +cd "$REPO_ROOT" + +echo "๐Ÿ” GitHub Secrets Setup Helper for APK Signing" +echo "================================================" +echo "" + +# Colors for output +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +RED='\033[0;31m' +NC='\033[0m' # No Color + +# Track successful secret generations +SECRETS_FOUND=0 +TOTAL_SECRETS=24 + +# ============================================================================= +# Helper Functions +# ============================================================================= + +print_secret_config() { + local app=$1 + local env=$2 + local keystore_path=$3 + local password=$4 + local alias=$5 + local key_password=$6 + + local app_upper=$(echo "$app" | tr '[:lower:]' '[:upper:]') + local env_upper=$(echo "$env" | tr '[:lower:]' '[:upper:]') + + echo "" + echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" + echo " ${app_upper} Mobile - ${env_upper} Environment" + echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" + + if [ -f "$keystore_path" ]; then + echo -e "${GREEN}โœ… Keystore found:${NC} $keystore_path" + + # Show keystore info + echo "" + echo "๐Ÿ“‹ Keystore Information:" + keytool -list -v -keystore "$keystore_path" -storepass "$password" 2>/dev/null | head -n 15 || echo " (Use keytool to inspect)" + + # Generate base64 + echo "" + echo "๐Ÿ“ฆ Base64 Encoded Keystore:" + echo "" + BASE64_OUTPUT=$(base64 -i "$keystore_path") + echo "$BASE64_OUTPUT" + echo "" + + echo "GitHub Secrets to create:" + echo "" + echo " ${app_upper}_KEYSTORE_${env_upper}_BASE64" + echo " ${app_upper}_KEYSTORE_PASSWORD_${env_upper} = $password" + echo " ${app_upper}_KEY_ALIAS_${env_upper} = $alias" + echo " ${app_upper}_KEY_PASSWORD_${env_upper} = $key_password" + echo "" + + # Increment success counter (4 secrets per keystore) + SECRETS_FOUND=$((SECRETS_FOUND + 4)) + + else + echo -e "${YELLOW}โš ๏ธ Keystore not found:${NC} $keystore_path" + echo "" + echo "This keystore should be stored securely (CodeMagic or secure storage)." + echo "" + fi +} + +# ============================================================================= +# Worker Mobile (Staff App) +# ============================================================================= + +echo "" +echo "โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" +echo " WORKER MOBILE (Staff App) Configuration" +echo "โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" + +# DEV Environment +print_secret_config \ + "worker" \ + "dev" \ + "$REPO_ROOT/apps/mobile/apps/staff/android/app/krow_with_us_staff_dev.jks" \ + "krowwithus" \ + "krow_staff_dev" \ + "krowwithus" + +# STAGING Environment +print_secret_config \ + "worker" \ + "staging" \ + "$REPO_ROOT/keystores/krow_staff_staging.jks" \ + "YOUR_STAGING_PASSWORD" \ + "krow_staff_staging" \ + "YOUR_STAGING_KEY_PASSWORD" + +# PROD Environment +print_secret_config \ + "worker" \ + "prod" \ + "$REPO_ROOT/keystores/krow_staff_prod.jks" \ + "YOUR_PROD_PASSWORD" \ + "krow_staff_prod" \ + "YOUR_PROD_KEY_PASSWORD" + +# ============================================================================= +# Client Mobile +# ============================================================================= + +echo "" +echo "โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" +echo " CLIENT MOBILE Configuration" +echo "โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" + +# DEV Environment +print_secret_config \ + "client" \ + "dev" \ + "$REPO_ROOT/apps/mobile/apps/client/android/app/krow_with_us_client_dev.jks" \ + "krowwithus" \ + "krow_client_dev" \ + "krowwithus" + +# STAGING Environment +print_secret_config \ + "client" \ + "staging" \ + "$REPO_ROOT/keystores/krow_client_staging.jks" \ + "YOUR_STAGING_PASSWORD" \ + "krow_client_staging" \ + "YOUR_STAGING_KEY_PASSWORD" + +# PROD Environment +print_secret_config \ + "client" \ + "prod" \ + "$REPO_ROOT/keystores/krow_client_prod.jks" \ + "YOUR_PROD_PASSWORD" \ + "krow_client_prod" \ + "YOUR_PROD_KEY_PASSWORD" + +# ============================================================================= +# Summary +# ============================================================================= + +echo "" +echo "โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" +echo " SUMMARY" +echo "โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" +echo "" +echo "Total secrets needed: ${TOTAL_SECRETS}" +echo "Secrets successfully generated: ${SECRETS_FOUND}" +echo "" +echo " โ€ข 6 keystores (base64 encoded)" +echo " โ€ข 6 keystore passwords" +echo " โ€ข 6 key aliases" +echo " โ€ข 6 key passwords" +echo "" + +if [ $SECRETS_FOUND -gt 0 ]; then + echo "Generated secrets to add to GitHub:" + echo "" + + # Worker Dev Secrets + if [ -f "$REPO_ROOT/apps/mobile/apps/staff/android/app/krow_with_us_staff_dev.jks" ]; then + echo " โœ… WORKER_KEYSTORE_DEV_BASE64" + echo " $(base64 -i "$REPO_ROOT/apps/mobile/apps/staff/android/app/krow_with_us_staff_dev.jks")" + echo "" + echo " โœ… WORKER_KEYSTORE_PASSWORD_DEV" + echo " krowwithus" + echo "" + echo " โœ… WORKER_KEY_ALIAS_DEV" + echo " krow_staff_dev" + echo "" + echo " โœ… WORKER_KEY_PASSWORD_DEV" + echo " krowwithus" + echo "" + fi + + # Client Dev Secrets + if [ -f "$REPO_ROOT/apps/mobile/apps/client/android/app/krow_with_us_client_dev.jks" ]; then + echo " โœ… CLIENT_KEYSTORE_DEV_BASE64" + echo " $(base64 -i "$REPO_ROOT/apps/mobile/apps/client/android/app/krow_with_us_client_dev.jks")" + echo "" + echo " โœ… CLIENT_KEYSTORE_PASSWORD_DEV" + echo " krowwithus" + echo "" + echo " โœ… CLIENT_KEY_ALIAS_DEV" + echo " krow_client_dev" + echo "" + echo " โœ… CLIENT_KEY_PASSWORD_DEV" + echo " krowwithus" + echo "" + fi +fi + +if [ $SECRETS_FOUND -lt $TOTAL_SECRETS ]; then + echo "Missing secrets (keystores not found):" + echo "" + + if [ ! -f "$REPO_ROOT/keystores/krow_staff_staging.jks" ]; then + echo " โš ๏ธ WORKER_KEYSTORE_STAGING_BASE64" + echo " โš ๏ธ WORKER_KEYSTORE_PASSWORD_STAGING" + echo " โš ๏ธ WORKER_KEY_ALIAS_STAGING" + echo " โš ๏ธ WORKER_KEY_PASSWORD_STAGING" + fi + + if [ ! -f "$REPO_ROOT/keystores/krow_staff_prod.jks" ]; then + echo " โš ๏ธ WORKER_KEYSTORE_PROD_BASE64" + echo " โš ๏ธ WORKER_KEYSTORE_PASSWORD_PROD" + echo " โš ๏ธ WORKER_KEY_ALIAS_PROD" + echo " โš ๏ธ WORKER_KEY_PASSWORD_PROD" + fi + + if [ ! -f "$REPO_ROOT/keystores/krow_client_staging.jks" ]; then + echo " โš ๏ธ CLIENT_KEYSTORE_STAGING_BASE64" + echo " โš ๏ธ CLIENT_KEYSTORE_PASSWORD_STAGING" + echo " โš ๏ธ CLIENT_KEY_ALIAS_STAGING" + echo " โš ๏ธ CLIENT_KEY_PASSWORD_STAGING" + fi + + if [ ! -f "$REPO_ROOT/keystores/krow_client_prod.jks" ]; then + echo " โš ๏ธ CLIENT_KEYSTORE_PROD_BASE64" + echo " โš ๏ธ CLIENT_KEYSTORE_PASSWORD_PROD" + echo " โš ๏ธ CLIENT_KEY_ALIAS_PROD" + echo " โš ๏ธ CLIENT_KEY_PASSWORD_PROD" + fi + + echo "" + echo "Retrieve missing keystores from CodeMagic Team Settings or secure storage." +fi + +echo "" +echo "To configure GitHub Secrets:" +echo "" +echo " 1. Go to: https://github.com/Oloodi/krow-workforce/settings/secrets/actions" +echo " 2. Click 'New repository secret'" +echo " 3. Add each secret listed above" +echo "" +echo "For complete documentation, see:" +echo " docs/RELEASE/APK_SIGNING_SETUP.md" +echo "" +echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" +echo "" diff --git a/.github/scripts/verify-apk-signature.sh b/.github/scripts/verify-apk-signature.sh new file mode 100755 index 00000000..eec7088a --- /dev/null +++ b/.github/scripts/verify-apk-signature.sh @@ -0,0 +1,59 @@ +#!/bin/bash + +# ============================================================================= +# Verify APK Signature +# ============================================================================= +# This script verifies that an APK is properly signed and displays +# certificate information +# +# Usage: +# ./verify-apk-signature.sh +# +# Arguments: +# apk_path - Path to the APK file to verify +# ============================================================================= + +set -e + +APK_PATH="$1" + +if [ -z "$APK_PATH" ]; then + echo "โŒ Error: Missing APK path" >&2 + echo "Usage: $0 " >&2 + exit 1 +fi + +if [ ! -f "$APK_PATH" ]; then + echo "โŒ APK not found at: $APK_PATH" >&2 + exit 1 +fi + +echo "๐Ÿ” Verifying APK signature..." >&2 + +# Check if APK is signed +if jarsigner -verify -verbose "$APK_PATH" 2>&1 | grep -q "jar verified"; then + echo "โœ… APK is properly signed!" >&2 + + # Extract certificate details + echo "" >&2 + echo "๐Ÿ“œ Certificate Details:" >&2 + jarsigner -verify -verbose -certs "$APK_PATH" 2>&1 | grep -A 3 "X.509" || true + + # Get signer info + echo "" >&2 + echo "๐Ÿ”‘ Signer Information:" >&2 + keytool -printcert -jarfile "$APK_PATH" | head -n 15 + +else + echo "โš ๏ธ WARNING: APK signature verification failed or APK is unsigned!" >&2 + echo "" >&2 + echo "This may happen if:" >&2 + echo " 1. GitHub Secrets are not configured for this environment" >&2 + echo " 2. Keystore credentials are incorrect" >&2 + echo " 3. Build configuration didn't apply signing" >&2 + echo "" >&2 + echo "See: docs/RELEASE/APK_SIGNING_SETUP.md for setup instructions" >&2 + + # Don't fail the build, just warn + # exit 1 +fi diff --git a/.github/workflows/backend-foundation.yml b/.github/workflows/backend-foundation.yml index 0e408f8f..a4a7d777 100644 --- a/.github/workflows/backend-foundation.yml +++ b/.github/workflows/backend-foundation.yml @@ -1,14 +1,7 @@ name: Backend Foundation on: - pull_request: - branches: - - dev - - main - push: - branches: - - dev - - main + workflow_dispatch: jobs: backend-foundation-makefile: diff --git a/.github/workflows/hotfix-branch-creation.yml b/.github/workflows/hotfix-branch-creation.yml new file mode 100644 index 00000000..0dcaed0f --- /dev/null +++ b/.github/workflows/hotfix-branch-creation.yml @@ -0,0 +1,332 @@ +name: ๐Ÿšจ Hotfix Branch Creation + +on: + workflow_dispatch: + inputs: + app: + description: '๐Ÿ“ฆ Product' + required: true + type: choice + options: + - worker-mobile-app + - client-mobile-app + tag: + description: '๐Ÿท๏ธ Current Tag (e.g., krow-withus-worker-mobile/prod-v0.1.0 or dev/stage)' + required: true + type: string + issue_description: + description: '๐Ÿ“ Brief issue description' + required: true + type: string + +jobs: + create-hotfix-branch: + name: ๐Ÿšจ Create Hotfix Branch + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + + steps: + - name: ๐Ÿ“ฅ Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: ๐Ÿ” Validate tag exists + id: validate_tag + run: | + TAG="${{ github.event.inputs.tag }}" + + if ! git rev-parse "$TAG" >/dev/null 2>&1; then + echo "โŒ Error: Tag '$TAG' does not exist" + echo "Available tags:" + git tag -l "krow-withus-*-mobile/*" | tail -20 + exit 1 + fi + + echo "โœ… Tag exists: $TAG" + + # Extract version from tag + VERSION=$(echo "$TAG" | grep -oP 'v\K[0-9]+\.[0-9]+\.[0-9]+' || echo "") + if [ -z "$VERSION" ]; then + echo "โŒ Error: Could not extract version from tag" + exit 1 + fi + + echo "current_version=${VERSION}" >> $GITHUB_OUTPUT + echo "๐Ÿ“Œ Current version: $VERSION" + + - name: ๐Ÿ”ข Calculate hotfix version + id: hotfix_version + run: | + CURRENT="${{ steps.validate_tag.outputs.current_version }}" + + # Split version into parts + IFS='.' read -r MAJOR MINOR PATCH <<< "$CURRENT" + + # Increment PATCH version + NEW_PATCH=$((PATCH + 1)) + HOTFIX_VERSION="${MAJOR}.${MINOR}.${NEW_PATCH}" + + echo "hotfix_version=${HOTFIX_VERSION}" >> $GITHUB_OUTPUT + echo "๐Ÿ†• Hotfix version: $HOTFIX_VERSION" + + - name: ๐ŸŒฟ Generate branch name + id: branch + run: | + APP="${{ github.event.inputs.app }}" + VERSION="${{ steps.hotfix_version.outputs.hotfix_version }}" + + # Strip -mobile-app suffix for cleaner branch names + APP_CLEAN=$(echo "$APP" | sed 's/-mobile-app$//') + + BRANCH_NAME="hotfix/krow-withus-${APP_CLEAN}-mobile-v${VERSION}" + echo "branch_name=${BRANCH_NAME}" >> $GITHUB_OUTPUT + echo "๐ŸŒฟ Branch to create: $BRANCH_NAME" + + - name: ๐Ÿ” Check if hotfix branch already exists + run: | + BRANCH="${{ steps.branch.outputs.branch_name }}" + + if git ls-remote --heads origin "$BRANCH" | grep -q "$BRANCH"; then + echo "โŒ Error: Branch $BRANCH already exists" + exit 1 + fi + + echo "โœ… Branch does not exist, proceeding..." + + - name: ๐ŸŒฟ Create hotfix branch from tag + run: | + TAG="${{ github.event.inputs.tag }}" + BRANCH="${{ steps.branch.outputs.branch_name }}" + + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + + # Checkout the tag + git checkout "$TAG" + + # Create new branch + git checkout -b "$BRANCH" + + echo "โœ… Created branch $BRANCH from tag $TAG" + + - name: ๐Ÿ“ Update version files + id: update_versions + run: | + APP="${{ github.event.inputs.app }}" + HOTFIX_VERSION="${{ steps.hotfix_version.outputs.hotfix_version }}" + + if [ "$APP" = "worker-mobile-app" ]; then + PUBSPEC_PATH="apps/mobile/apps/staff/pubspec.yaml" + CHANGELOG_PATH="apps/mobile/apps/staff/CHANGELOG.md" + APP_NAME="Staff Product" + else + PUBSPEC_PATH="apps/mobile/apps/client/pubspec.yaml" + CHANGELOG_PATH="apps/mobile/apps/client/CHANGELOG.md" + APP_NAME="Client Product" + fi + + # Update pubspec.yaml version + if [ -f "$PUBSPEC_PATH" ]; then + # Extract current version and build number + CURRENT_VERSION_LINE=$(grep "^version:" "$PUBSPEC_PATH") + CURRENT_BUILD=$(echo "$CURRENT_VERSION_LINE" | grep -oP '\+\K[0-9]+' || echo "1") + NEW_BUILD=$((CURRENT_BUILD + 1)) + + # Update version line + sed -i "s/^version:.*/version: ${HOTFIX_VERSION}+${NEW_BUILD}/" "$PUBSPEC_PATH" + + echo "โœ… Updated $PUBSPEC_PATH to ${HOTFIX_VERSION}+${NEW_BUILD}" + echo "updated_files=true" >> $GITHUB_OUTPUT + else + echo "โš ๏ธ Warning: $PUBSPEC_PATH not found" + echo "updated_files=false" >> $GITHUB_OUTPUT + fi + + - name: ๐Ÿ“‹ Add CHANGELOG entry + run: | + APP="${{ github.event.inputs.app }}" + HOTFIX_VERSION="${{ steps.hotfix_version.outputs.hotfix_version }}" + ISSUE="${{ github.event.inputs.issue_description }}" + + if [ "$APP" = "worker-mobile-app" ]; then + CHANGELOG_PATH="apps/mobile/apps/staff/CHANGELOG.md" + APP_NAME="Staff Product" + else + CHANGELOG_PATH="apps/mobile/apps/client/CHANGELOG.md" + APP_NAME="Client Product" + fi + + if [ -f "$CHANGELOG_PATH" ]; then + DATE=$(date +%Y-%m-%d) + + # Extract title and body + TITLE=$(head -n 1 "$CHANGELOG_PATH") + BODY=$(tail -n +2 "$CHANGELOG_PATH") + + # Rebuild CHANGELOG with hotfix entry + echo "$TITLE" > "$CHANGELOG_PATH" + echo "" >> "$CHANGELOG_PATH" + echo "## [${HOTFIX_VERSION}] - ${DATE} - HOTFIX" >> "$CHANGELOG_PATH" + echo "" >> "$CHANGELOG_PATH" + echo "### Fixed" >> "$CHANGELOG_PATH" + echo "- ${ISSUE}" >> "$CHANGELOG_PATH" + echo "" >> "$CHANGELOG_PATH" + echo "---" >> "$CHANGELOG_PATH" + echo "" >> "$CHANGELOG_PATH" + echo "$BODY" >> "$CHANGELOG_PATH" + + echo "โœ… Added CHANGELOG entry for hotfix $HOTFIX_VERSION" + else + echo "โš ๏ธ Warning: $CHANGELOG_PATH not found" + fi + + - name: ๐Ÿ’พ Commit version changes + run: | + HOTFIX_VERSION="${{ steps.hotfix_version.outputs.hotfix_version }}" + ISSUE="${{ github.event.inputs.issue_description }}" + + git add -A + git commit -m "chore: prepare hotfix v${HOTFIX_VERSION} + +HOTFIX: ${ISSUE} + +- Bump version to ${HOTFIX_VERSION} +- Add CHANGELOG entry +- Ready for bug fix commits + +From tag: ${{ github.event.inputs.tag }}" + + echo "โœ… Committed version changes" + + - name: ๐Ÿš€ Push hotfix branch + run: | + BRANCH="${{ steps.branch.outputs.branch_name }}" + + git push origin "$BRANCH" + + echo "โœ… Pushed branch: $BRANCH" + + - name: ๐Ÿ“„ Create Pull Request + id: create_pr + env: + GH_TOKEN: ${{ github.token }} + run: | + BRANCH="${{ steps.branch.outputs.branch_name }}" + HOTFIX_VERSION="${{ steps.hotfix_version.outputs.hotfix_version }}" + ISSUE="${{ github.event.inputs.issue_description }}" + APP="${{ github.event.inputs.app }}" + + # Strip -mobile-app suffix for cleaner tag names + APP_CLEAN=$(echo "$APP" | sed 's/-mobile-app$//') + + if [ "$APP" = "worker-mobile-app" ]; then + APP_DISPLAY="Worker Product" + else + APP_DISPLAY="Client Product" + fi + + PR_TITLE="๐Ÿšจ HOTFIX: ${APP_DISPLAY} v${HOTFIX_VERSION} - ${ISSUE}" + + PR_BODY="## ๐Ÿšจ HOTFIX - URGENT FIX + +**App:** ${APP_DISPLAY} +**Version:** ${HOTFIX_VERSION} +**From:** \`${{ github.event.inputs.tag }}\` + +### Issue +${ISSUE} + +### Impact + + +### Solution + + +### Testing + + +--- + +## โš ๏ธ Hotfix Process + +1. โœ… Hotfix branch created +2. โณ **NEXT:** Make your bug fix commits to this branch +3. โณ Test the fix locally +4. โณ Request expedited review (< 15 minutes) +5. โณ Merge to main and create production tag + +### To add your fix: +\`\`\`bash +git checkout $BRANCH +# Make your changes +git commit -m \"fix: [description]\" +git push origin $BRANCH +\`\`\` + +### After merging: +\`\`\`bash +# Tag and release +git checkout main +git pull origin main +git tag -a krow-withus-${APP_CLEAN}-mobile/prod-v${HOTFIX_VERSION} -m \"HOTFIX: ${ISSUE}\" +git push origin krow-withus-${APP_CLEAN}-mobile/prod-v${HOTFIX_VERSION} +\`\`\` + +--- + +**Ref:** [Hotfix Process Documentation](../docs/release/HOTFIX_PROCESS.md)" + + # Create PR + PR_URL=$(gh pr create \ + --base main \ + --head "$BRANCH" \ + --title "$PR_TITLE" \ + --body "$PR_BODY" \ + --label "hotfix,urgent,production") + + echo "pr_url=${PR_URL}" >> $GITHUB_OUTPUT + echo "โœ… Pull Request created: $PR_URL" + + - name: ๐Ÿ“Š Hotfix Summary + run: | + # Strip -mobile-app suffix for cleaner tag names + APP_CLEAN=$(echo "${{ github.event.inputs.app }}" | sed 's/-mobile-app$//') + + echo "## ๐Ÿšจ Hotfix Branch Created" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "**App:** ${{ github.event.inputs.app }}" >> $GITHUB_STEP_SUMMARY + echo "**Issue:** ${{ github.event.inputs.issue_description }}" >> $GITHUB_STEP_SUMMARY + echo "**From Tag:** \`${{ github.event.inputs.tag }}\`" >> $GITHUB_STEP_SUMMARY + echo "**Current Version:** ${{ steps.validate_tag.outputs.current_version }}" >> $GITHUB_STEP_SUMMARY + echo "**Hotfix Version:** ${{ steps.hotfix_version.outputs.hotfix_version }}" >> $GITHUB_STEP_SUMMARY + echo "**Branch:** \`${{ steps.branch.outputs.branch_name }}\`" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "### ๐Ÿ”ง Next Steps" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "1. **Checkout the hotfix branch:**" >> $GITHUB_STEP_SUMMARY + echo " \`\`\`bash" >> $GITHUB_STEP_SUMMARY + echo " git fetch origin" >> $GITHUB_STEP_SUMMARY + echo " git checkout ${{ steps.branch.outputs.branch_name }}" >> $GITHUB_STEP_SUMMARY + echo " \`\`\`" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "2. **Make your bug fix(es)** - Keep changes minimal!" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "3. **Test locally** - Verify the fix works" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "4. **Request expedited review** - Target < 15 minutes" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "5. **Merge PR and create production tag:**" >> $GITHUB_STEP_SUMMARY + echo " \`\`\`bash" >> $GITHUB_STEP_SUMMARY + echo " git checkout main" >> $GITHUB_STEP_SUMMARY + echo " git pull origin main" >> $GITHUB_STEP_SUMMARY + echo " git tag -a krow-withus-${APP_CLEAN}-mobile/prod-v${{ steps.hotfix_version.outputs.hotfix_version }} -m \"HOTFIX: ${{ github.event.inputs.issue_description }}\"" >> $GITHUB_STEP_SUMMARY + echo " git push origin krow-withus-${APP_CLEAN}-mobile/prod-v${{ steps.hotfix_version.outputs.hotfix_version }}" >> $GITHUB_STEP_SUMMARY + echo " \`\`\`" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + + if [ -n "${{ steps.create_pr.outputs.pr_url }}" ]; then + echo "**Pull Request:** ${{ steps.create_pr.outputs.pr_url }}" >> $GITHUB_STEP_SUMMARY + fi diff --git a/.github/workflows/mobile-ci.yml b/.github/workflows/mobile-ci.yml index 1a439740..910576de 100644 --- a/.github/workflows/mobile-ci.yml +++ b/.github/workflows/mobile-ci.yml @@ -1,16 +1,7 @@ name: Mobile CI on: - pull_request: - paths: - - 'apps/mobile/**' - - '.github/workflows/mobile-ci.yml' - push: - branches: - - main - paths: - - 'apps/mobile/**' - - '.github/workflows/mobile-ci.yml' + workflow_dispatch: jobs: detect-changes: diff --git a/.github/workflows/product-release.yml b/.github/workflows/product-release.yml new file mode 100644 index 00000000..7e72e4ec --- /dev/null +++ b/.github/workflows/product-release.yml @@ -0,0 +1,289 @@ +name: ๐Ÿ“ฆ Product Release + +on: + workflow_dispatch: + inputs: + app: + description: '๐Ÿ“ฆ Product' + required: true + type: choice + options: + - worker-mobile-app + - client-mobile-app + environment: + description: '๐ŸŒ Environment' + required: true + type: choice + options: + - dev + - stage + - prod + create_github_release: + description: '๐Ÿ“ฆ Create GitHub Release' + required: true + type: boolean + default: true + prerelease: + description: '๐Ÿ”– Mark as Pre-release' + required: false + type: boolean + default: false + +jobs: + validate-and-create-release: + name: ๐Ÿš€ Create Product Release + runs-on: ubuntu-latest + permissions: + contents: write + outputs: + version: ${{ steps.version.outputs.version }} + tag_name: ${{ steps.tag.outputs.tag_name }} + + steps: + - name: ๐Ÿ“ฅ Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: ๐Ÿƒ๐Ÿพโ€โ™‚๏ธ Make scripts executable + run: | + chmod +x .github/scripts/*.sh + echo "โœ… Scripts are now executable" + + - name: ๐Ÿ“– Extract version from version file + id: version + run: | + VERSION=$(.github/scripts/extract-version.sh "${{ github.event.inputs.app }}") + echo "version=${VERSION}" >> $GITHUB_OUTPUT + echo "๐Ÿ“Œ Extracted version: ${VERSION}" + + - name: ๐Ÿท๏ธ Generate tag name + id: tag + run: | + TAG_NAME=$(.github/scripts/generate-tag-name.sh \ + "${{ github.event.inputs.app }}" \ + "${{ github.event.inputs.environment }}" \ + "${{ steps.version.outputs.version }}") + echo "tag_name=${TAG_NAME}" >> $GITHUB_OUTPUT + echo "๐ŸŽฏ Tag to create: ${TAG_NAME}" + + - name: ๐Ÿ” Check if tag already exists + run: | + TAG_NAME="${{ steps.tag.outputs.tag_name }}" + if git rev-parse "$TAG_NAME" >/dev/null 2>&1; then + echo "โŒ Error: Tag $TAG_NAME already exists" + echo "๐Ÿ’ก Tip: Update the version in the version file before creating a new release" + exit 1 + fi + echo "โœ… Tag does not exist, proceeding..." + + - name: ๐Ÿ“‹ Extract release notes from CHANGELOG + id: release_notes + run: | + .github/scripts/extract-release-notes.sh \ + "${{ github.event.inputs.app }}" \ + "${{ steps.version.outputs.version }}" \ + "${{ github.event.inputs.environment }}" \ + "${{ steps.tag.outputs.tag_name }}" \ + "/tmp/release_notes.md" + echo "notes_file=/tmp/release_notes.md" >> $GITHUB_OUTPUT + + - name: ๐Ÿท๏ธ Create Git Tag + run: | + TAG_NAME="${{ steps.tag.outputs.tag_name }}" + APP="${{ github.event.inputs.app }}" + ENV="${{ github.event.inputs.environment }}" + VERSION="${{ steps.version.outputs.version }}" + + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + + git tag -a "$TAG_NAME" -m "๐Ÿš€ Release ${APP} product ${VERSION} to ${ENV}" + git push origin "$TAG_NAME" + + echo "โœ… Tag created and pushed: $TAG_NAME" + + - name: ๐Ÿ“ฆ Create GitHub Release + if: ${{ github.event.inputs.create_github_release == 'true' }} + env: + GH_TOKEN: ${{ github.token }} + run: | + TAG_NAME="${{ steps.tag.outputs.tag_name }}" + APP="${{ github.event.inputs.app }}" + ENV="${{ github.event.inputs.environment }}" + VERSION="${{ steps.version.outputs.version }}" + + # Generate release title + if [ "$APP" = "worker-mobile-app" ]; then + APP_DISPLAY="Worker Mobile Application" + else + APP_DISPLAY="Client Mobile Application" + fi + + ENV_UPPER=$(echo "$ENV" | tr '[:lower:]' '[:upper:]') + RELEASE_NAME="Krow With Us - ${APP_DISPLAY} - ${ENV_UPPER} - v${VERSION}" + + echo "๐Ÿ“ฆ Creating GitHub Release: $RELEASE_NAME" + + # Create release + if [ "${{ github.event.inputs.prerelease }}" = "true" ]; then + gh release create "$TAG_NAME" \ + --title "$RELEASE_NAME" \ + --notes-file "${{ steps.release_notes.outputs.notes_file }}" \ + --prerelease + echo "๐Ÿ”– Pre-release created successfully" + else + gh release create "$TAG_NAME" \ + --title "$RELEASE_NAME" \ + --notes-file "${{ steps.release_notes.outputs.notes_file }}" + echo "โœ… Release created successfully" + fi + + - name: ๐Ÿ“Š Generate Release Summary + run: | + .github/scripts/create-release-summary.sh \ + "${{ github.event.inputs.app }}" \ + "${{ github.event.inputs.environment }}" \ + "${{ steps.version.outputs.version }}" \ + "${{ steps.tag.outputs.tag_name }}" + + build-mobile-artifacts: + name: ๐Ÿ“ฑ Build Mobile APK + runs-on: ubuntu-latest + needs: validate-and-create-release + if: ${{ github.event.inputs.app == 'worker-mobile-app' || github.event.inputs.app == 'client-mobile-app' }} + permissions: + contents: write + + steps: + - name: ๐Ÿ“ฅ Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: ๐ŸŸข Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: ๐Ÿ”ฅ Install Firebase CLI + run: | + npm install -g firebase-tools + firebase --version + echo "โ„น๏ธ Note: Firebase CLI installed for Data Connect SDK generation" + echo "โ„น๏ธ If SDK generation fails, ensure Data Connect SDK files are committed to repo" + + - name: โ˜• Setup Java + uses: actions/setup-java@v4 + with: + distribution: 'zulu' + java-version: '17' + + - name: ๐Ÿฆ Setup Flutter + uses: subosito/flutter-action@v2 + with: + flutter-version: '3.38.x' + channel: 'stable' + cache: true + + - name: ๐Ÿ”ง Install Melos + run: | + dart pub global activate melos + echo "$HOME/.pub-cache/bin" >> $GITHUB_PATH + + - name: ๐Ÿ“ฆ Install Dependencies + run: | + make mobile-install + + - name: ๐Ÿ” Setup APK Signing + env: + # Worker Mobile (Staff App) Secrets + WORKER_KEYSTORE_DEV_BASE64: ${{ secrets.WORKER_KEYSTORE_DEV_BASE64 }} + WORKER_KEYSTORE_STAGING_BASE64: ${{ secrets.WORKER_KEYSTORE_STAGING_BASE64 }} + WORKER_KEYSTORE_PROD_BASE64: ${{ secrets.WORKER_KEYSTORE_PROD_BASE64 }} + WORKER_KEYSTORE_PASSWORD_DEV: ${{ secrets.WORKER_KEYSTORE_PASSWORD_DEV }} + WORKER_KEYSTORE_PASSWORD_STAGING: ${{ secrets.WORKER_KEYSTORE_PASSWORD_STAGING }} + WORKER_KEYSTORE_PASSWORD_PROD: ${{ secrets.WORKER_KEYSTORE_PASSWORD_PROD }} + WORKER_KEY_ALIAS_DEV: ${{ secrets.WORKER_KEY_ALIAS_DEV }} + WORKER_KEY_ALIAS_STAGING: ${{ secrets.WORKER_KEY_ALIAS_STAGING }} + WORKER_KEY_ALIAS_PROD: ${{ secrets.WORKER_KEY_ALIAS_PROD }} + WORKER_KEY_PASSWORD_DEV: ${{ secrets.WORKER_KEY_PASSWORD_DEV }} + WORKER_KEY_PASSWORD_STAGING: ${{ secrets.WORKER_KEY_PASSWORD_STAGING }} + WORKER_KEY_PASSWORD_PROD: ${{ secrets.WORKER_KEY_PASSWORD_PROD }} + + # Client Mobile Secrets + CLIENT_KEYSTORE_DEV_BASE64: ${{ secrets.CLIENT_KEYSTORE_DEV_BASE64 }} + CLIENT_KEYSTORE_STAGING_BASE64: ${{ secrets.CLIENT_KEYSTORE_STAGING_BASE64 }} + CLIENT_KEYSTORE_PROD_BASE64: ${{ secrets.CLIENT_KEYSTORE_PROD_BASE64 }} + CLIENT_KEYSTORE_PASSWORD_DEV: ${{ secrets.CLIENT_KEYSTORE_PASSWORD_DEV }} + CLIENT_KEYSTORE_PASSWORD_STAGING: ${{ secrets.CLIENT_KEYSTORE_PASSWORD_STAGING }} + CLIENT_KEYSTORE_PASSWORD_PROD: ${{ secrets.CLIENT_KEYSTORE_PASSWORD_PROD }} + CLIENT_KEY_ALIAS_DEV: ${{ secrets.CLIENT_KEY_ALIAS_DEV }} + CLIENT_KEY_ALIAS_STAGING: ${{ secrets.CLIENT_KEY_ALIAS_STAGING }} + CLIENT_KEY_ALIAS_PROD: ${{ secrets.CLIENT_KEY_ALIAS_PROD }} + CLIENT_KEY_PASSWORD_DEV: ${{ secrets.CLIENT_KEY_PASSWORD_DEV }} + CLIENT_KEY_PASSWORD_STAGING: ${{ secrets.CLIENT_KEY_PASSWORD_STAGING }} + CLIENT_KEY_PASSWORD_PROD: ${{ secrets.CLIENT_KEY_PASSWORD_PROD }} + run: | + .github/scripts/setup-apk-signing.sh \ + "${{ github.event.inputs.app }}" \ + "${{ github.event.inputs.environment }}" \ + "${{ runner.temp }}" + + - name: ๐Ÿ—๏ธ Build APK + id: build_apk + run: | + APP="${{ github.event.inputs.app }}" + + if [ "$APP" = "worker-mobile-app" ]; then + echo "๐Ÿ“ฑ Building Staff (Worker) APK..." + make mobile-staff-build PLATFORM=apk MODE=release + APP_NAME="staff" + else + echo "๐Ÿ“ฑ Building Client APK..." + make mobile-client-build PLATFORM=apk MODE=release + APP_NAME="client" + fi + + # Find the generated APK (Flutter places it in build/app/outputs/flutter-apk/) + APK_PATH=$(find apps/mobile/apps/${APP_NAME}/build/app/outputs/flutter-apk -name "app-release.apk" 2>/dev/null | head -n 1) + + # Fallback to searching entire apps directory if not found + if [ -z "$APK_PATH" ]; then + APK_PATH=$(find apps/mobile/apps/${APP_NAME} -name "app-release.apk" | head -n 1) + fi + + if [ -z "$APK_PATH" ]; then + echo "โŒ Error: APK not found!" + echo "Searched in apps/mobile/apps/${APP_NAME}/" + find apps/mobile/apps/${APP_NAME} -name "*.apk" || echo "No APK files found" + exit 1 + fi + + echo "โœ… APK built successfully: $APK_PATH" + echo "app_name=${APP_NAME}" >> $GITHUB_OUTPUT + echo "apk_path=${APK_PATH}" >> $GITHUB_OUTPUT + + - name: โœ… Verify APK Signature + run: | + .github/scripts/verify-apk-signature.sh "${{ steps.build_apk.outputs.apk_path }}" + + - name: ๐Ÿ“ค Upload APK as Artifact + uses: actions/upload-artifact@v4 + with: + name: ${{ github.event.inputs.app }}-${{ needs.validate-and-create-release.outputs.version }}-${{ github.event.inputs.environment }} + path: apps/mobile/apps/${{ steps.build_apk.outputs.app_name }}/build/app/outputs/flutter-apk/app-release.apk + if-no-files-found: error + retention-days: 30 + + - name: ๐Ÿ“ฆ Attach APK to GitHub Release + if: ${{ github.event.inputs.create_github_release == 'true' }} + env: + GH_TOKEN: ${{ github.token }} + run: | + .github/scripts/attach-apk-to-release.sh \ + "${{ needs.validate-and-create-release.outputs.tag_name }}" \ + "${{ github.event.inputs.app }}" \ + "${{ steps.build_apk.outputs.app_name }}" \ + "${{ needs.validate-and-create-release.outputs.version }}" \ + "${{ github.event.inputs.environment }}" diff --git a/.github/workflows/web-quality.yml b/.github/workflows/web-quality.yml index 7280b333..dd955c5c 100644 --- a/.github/workflows/web-quality.yml +++ b/.github/workflows/web-quality.yml @@ -1,14 +1,7 @@ name: Web Quality on: - pull_request: - branches: - - dev - - main - push: - branches: - - dev - - main + workflow_dispatch: jobs: web-quality: diff --git a/Makefile b/Makefile index 4a029884..98d82e42 100644 --- a/Makefile +++ b/Makefile @@ -91,10 +91,11 @@ help: @echo "" @echo " ๐Ÿ› ๏ธ DEVELOPMENT TOOLS" @echo " โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€" - @echo " make install-melos Install Melos globally (for mobile dev)" - @echo " make install-git-hooks Install git pre-push hook (protect main/dev)" - @echo " make sync-prototypes Sync prototypes from client-krow-poc repo" - @echo " make clean-branches Delete local branches (keeps main/dev/demo/**/protected)" + @echo " make install-melos Install Melos globally (for mobile dev)" + @echo " make install-git-hooks Install git pre-push hook (protect main/dev)" + @echo " make sync-prototypes Sync prototypes from client-krow-poc repo" + @echo " make clean-branches Delete local branches (keeps main/dev/demo/**/protected)" + @echo " make setup-mobile-ci-secrets Setup GitHub Secrets for mobile APK signing (CI/CD)" @echo "" @echo " โ„น๏ธ HELP" @echo " โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€" diff --git a/apps/mobile/apps/client/CHANGELOG.md b/apps/mobile/apps/client/CHANGELOG.md new file mode 100644 index 00000000..c2e2e024 --- /dev/null +++ b/apps/mobile/apps/client/CHANGELOG.md @@ -0,0 +1,230 @@ +# Client Mobile App - Change Log + +## [v0.0.1-m3] - Milestone 3 - 2026-02-15 + +### Added - Authentication & Onboarding +- Business email and password authentication +- Client account registration +- Business onboarding flow +- Company information setup + +### Added - Home Dashboard +- Welcome screen with business name +- Coverage statistics for today: + - Coverage percentage + - Workers checked in vs needed + - Open positions count +- Late workers alerts with visual indicators +- Today's estimated labor cost +- Upcoming shifts section +- Quick action buttons: + - Create Order + - Hubs management + +### Added - Hub Management +- Hubs page accessible from settings +- Hub creation flow: + - Hub name input + - Address autocomplete with Google Maps Places API + - Hub creation confirmation +- Hubs list view showing all created hubs +- Hub card display with name, address, and tag ID + +### Added - Order Creation +- Orders tab in bottom navigation +- "+ Post" button to create new orders +- Order type selection screen: + - One-Time orders (implemented) +- One-Time Order creation form: + - Order name + - Date picker + - Hub selection + - Position management: + - Role selection + - Worker count + - Start/end time + - Shift duration calculation + - Cost estimation +- Order creation confirmation + +### Added - Order Management +- Orders list view with: + - Order cards showing date, location, time + - Worker count (filled/needed) + - Coverage percentage bar + - Status indicators (OPEN, FILLED, IN PROGRESS) +- Order details view: + - Event name and location + - Roles and worker requirements + - Clock in/out times + - Estimated cost + - Coverage percentage + - Map integration with directions + +### Added - Coverage Monitoring +- Coverage tab in bottom navigation +- Real-time worker status dashboard: + - Checked In (green indicator) + - En Route (yellow indicator) + - Late (red indicator) + - Not Arrived status +- Color-coded status badges +- Worker information cards +- Active shift monitoring + +### Added - Navigation +- Bottom navigation bar with tabs: + - Coverage + - Billing + - Home + - Orders + - Reports +- Settings menu accessible from home screen +- Back navigation handling + +### Added - Settings +- Settings page with options: + - Hubs management + - Profile editing + - Notifications preferences + - Log out + +### Technical Features +- Firebase authentication integration +- Data Connect backend integration +- Google Maps Places API for address autocomplete +- Real-time worker status tracking +- Cost calculation engine +- Coverage percentage calculations + +### Known Limitations +- Orders require hub assignment +- Currently supports one-time orders only +- Order approval flow not yet implemented +- RAPID, Recurring, and Permanent order types are placeholders + +--- + +## [v0.0.1-m4] - Milestone 4 - 2026-03-05 + +### Added - Enhanced Authentication & Session Management +- Authentication session persistence across app restarts +- Automatic login with valid session tokens +- Improved user experience with seamless session handling + +### Added - RAPID Order Creation (AI-Powered) +- Voice input for order creation with audio recording +- Text input for order description +- Multi-platform audio recording support (iOS/Android) +- AI transcription service for voice-to-text conversion +- AI parsing to generate order drafts from natural language +- Same-day order support for urgent coverage needs +- Populated order form matching one-time order structure +- Edit AI-generated order before submission +- Quick order creation workflow +- Audio file upload for transcription +- RAPID order verification page with refinements +- Hub and role matching for order creation + +### Added - Recurring Order Support +- Recurring order creation flow +- Schedule configuration interface +- Recurring patterns (daily, weekly, custom) +- Recurring order management + +### Added - Permanent Order Support +- Permanent order creation flow +- Long-term position setup +- Permanent order management + +### Added - Enhanced Order Management +- Hide edit icon for past or completed orders +- Updated Reorder modal supporting all order types: + - One-Time reorder + - RAPID reorder + - Recurring reorder + - Permanent reorder +- Reorder functionality with order type awareness +- Hub manager assignment to orders +- Cost center entity linking to hubs +- Completion review UI with: + - Actions summary + - Amount display + - Info sections + - Worker listing +- Invoice management improvements + +### Added - Comprehensive Reports System +- Reports page with AI-powered insights +- Three AI-generated insights on reports landing page +- Six report types: + 1. **Daily Ops Report**: Daily operational metrics and statistics + 2. **Spend Report**: Labor cost analysis and spend tracking + 3. **Coverage Report**: Shift coverage analytics and trends + 4. **No-Show Report**: Worker attendance and no-show tracking + 5. **Performance Report**: Worker performance metrics and ratings + 6. *(Reserved for future report type)* + +### Added - Hub Management Enhancements +- Dedicated hub details interface +- Detailed hub information view +- Hub editing page (separate interface) +- Enhanced hub navigation + +### Added - Home Dashboard Enhancements +- Reorder quick action button +### Added - Home Dashboard Enhancements +- Reorder quick action button for fast order duplication +- Insights quick action button for AI analytics +- Direct access to AI insights from home +- Refactored home widgets with SectionLayout: + - Today's shifts section with titles + - Tomorrow's shifts section + - Coverage widget improvements + - Live activity widget enhancements + - Spending widget updates +- Full-width dividers for better visual separation +- Improved dashboard widget organization + +### Improved - User Experience +- Better order type selection flow +- Enhanced order creation UX across all types +- Improved reports navigation +- Better hub management interface +- Bottom navigation bar show/hide based on route changes +- Enhanced navigation robustness with error handling +- Improved invoice page layout with reordered titles +- Session management improvements with proper role validation +- Enhanced settings page navigation flow +- Better amount widget styling in completion review + +### Fixed +- Client app crash issues resolved +- Shift booking status inconsistencies fixed +- Session navigation errors corrected +- Formatting and code clarity improvements across codebase + +### Technical Features +- Backend transaction support for order creation +- Order validation (minimum hours check) +- Shift creation validation +- 24-hour cancellation policy enforcement +- Enhanced backend reporting APIs +- AI insights generation system +- Core API integration: + - RAPID order transcription endpoints + - Order parsing services + - File upload with signed URLs + - LLM services +- ApiService with Dio for standardized API requests +- DataConnectService integration across all repositories +- Enhanced session management with SessionListener +- Role-based session handling + +### Known Limitations +- RAPID order parsing requires clear voice/text input +- AI insights require sufficient historical data +- Reports may have limited data in early usage +- PDF export for reports not yet implemented + +--- diff --git a/apps/mobile/apps/client/pubspec.yaml b/apps/mobile/apps/client/pubspec.yaml index 7a71eecc..677133d7 100644 --- a/apps/mobile/apps/client/pubspec.yaml +++ b/apps/mobile/apps/client/pubspec.yaml @@ -1,7 +1,7 @@ name: krowwithus_client description: "KROW Client Application" publish_to: "none" -version: 0.0.1-IlianaClientM4 +version: 0.0.1-m4 resolution: workspace environment: diff --git a/apps/mobile/apps/staff/CHANGELOG.md b/apps/mobile/apps/staff/CHANGELOG.md new file mode 100644 index 00000000..9d81362d --- /dev/null +++ b/apps/mobile/apps/staff/CHANGELOG.md @@ -0,0 +1,193 @@ +# Staff Mobile App - Change Log + +## [v0.0.1-m3] - Milestone 3 - 2026-02-15 + +### Added - Authentication & Onboarding +- Phone number authentication with OTP verification +- Staff onboarding flow with profile setup +- Personal information collection (name, bio, languages) +- Preferred work locations selection +- Skills and industry selection + +### Added - Home Dashboard +- Welcome screen with personalized greeting +- Today's shifts section showing confirmed shifts +- Tomorrow's shifts preview +- Recommended shifts section based on profile +- Quick action buttons (Find Shifts, Availability, Messages, Earnings) + +### Added - Shift Management +- Find Shifts functionality to discover available work +- Shift details view showing: + - Business name and location + - Hourly rate and estimated earnings + - Date, start time, end time + - Job requirements + - Map integration with directions +- Shift booking/application process +- Booking confirmation dialog +- My Shifts view with week-by-week navigation +- Color-coded shift status (Confirmed, Pending, Completed) + +### Added - Clock In/Out +- Clock In page with slider interaction +- Clock Out page with slider interaction +- Automatic timestamp recording +- Shift status updates upon clock in/out +- Visual status indicators (green for checked in) + +### Added - Profile Management +- Profile tab with personal information +- Emergency Contact management: + - Contact name + - Relationship + - Phone number +- Bank Account linking for direct deposit +- Tax Forms section: + - W-4 form access + - I-9 form access +- Time Card view: + - Historical shift records + - Hours worked tracking + - Earnings history + +### Added - Navigation +- Bottom navigation bar with 5 tabs: + - Shifts + - Payments + - Home + - Clock In + - Profile +- Tab bar hiding on specific pages + +### Technical Features +- Firebase authentication integration +- Data Connect backend integration +- Google Maps integration for locations +- Phone verification system +- OTP code handling + +### Known Limitations +- Newly created orders don't appear immediately in Find Shifts (requires vendor approval) +- Limited to one-time order types in this milestone + +--- + +## [v0.0.1-m4] - Milestone 4 - 2026-03-05 + +### Added - Enhanced Authentication & Session Management +- Authentication session persistence across app restarts +- Automatic login with valid session tokens +- Improved user experience with seamless session handling + +### Added - Enhanced Shift Details +- Google Maps location display in shift details view +- Interactive map showing shift location +- Directions integration +- Shift requirements section showing: + - Required attire items (MUST HAVE) + - Preferred attire items (NICE TO HAVE) + - Other shift-specific requirements + +### Added - Attire Management +- Dedicated Attire screen in profile +- Camera and gallery support for attire photo capture +- Local image preview before submission +- Upload attire images for verification +- MUST HAVE attire items list +- NICE TO HAVE attire items list +- Attire photo gallery in profile +- Submit attire for review workflow +- Attire verification status tracking (Pending, Approved, Rejected) +- Attestation checkbox for attire accuracy confirmation +- Filtered attire items based on requirements + +### Added - Documents & Certificates Management +- Documents section in profile with verification status tracking +- Upload documents (ID, licenses, etc.) with: + - Camera or gallery selection + - File type validation + - Upload progress tracking + - Verification metadata +- Certificates management: + - Upload certificates with expiry dates + - Certificate number field + - Certificate type selection + - View existing certificates + - Delete certificates + - Verification status (Not Verified, Verified, Expired) +- Mandatory document flagging +- Document verification workflow + +### Added - Profile Enhancements +- FAQ (Frequently Asked Questions) screen +- Privacy and Security settings screen: + - Profile visibility toggle ("Hide account from business") + - Terms of Service document access + - Privacy Policy document access +- Preferred locations management: + - Dedicated edit screen + - Location search functionality + - Display selected locations +- Language selection interface: + - Spanish language support + - Success feedback on language change + - Persistent language preference +- Benefits overview section: + - Benefits listing with circular progress indicators + - Benefits dashboard integration +- Profile completion tracking for: + - Personal information + - Emergency contacts + - Experience + - Attire + - Documents + - Certificates + +### Added - Profile Completion Gating +- Navigation restrictions for incomplete profiles +- Only Home and Profile tabs accessible until profile is complete +- Profile completion checklist +- Guided onboarding completion flow + +### Improved - User Experience +- Enhanced shift details UI with better information hierarchy +- Improved profile section organization +- Better navigation flow for profile completion +- UiEmptyState widgets for better empty state handling: + - Bank account page empty state + - Home page when no shifts available +- Improved onboarding flow with refactored experience and personal info pages +- Enhanced emergency contact screen with info banner +- Refactored profile header with profile level badge ("KROWER I") +- Benefits card components with improved styling +- Bottom navigation bar show/hide based on route +- Tax forms page with progress overview +- Improved notice and file type banners for uploads +- Enhanced navigation robustness with proper error handling +- Immediate ID token refresh after sign-in to prevent unauthenticated requests + +### Fixed +- Profile completion status now updates correctly for emergency contacts +- Session handling improved to prevent data loss +- Navigation errors redirect to appropriate home page +- Locale synchronization by reloading from persistent storage after change + +### Technical Features +- Enhanced backend validation for shift acceptance +- Overlapping shift prevention +- Improved session management +- Document upload and storage integration +- Signed URL generation for file uploads +- Camera and gallery native device access +- File visibility controls (public/private) +- Core API services integration (verification, file upload, LLM) +- ApiService with Dio for standardized API requests +- Device services abstraction layer + +### Known Limitations +- Cannot accept overlapping shifts +- Shifts require manual confirmation in some cases +- Attire verification requires manual client approval + +--- diff --git a/apps/mobile/apps/staff/pubspec.yaml b/apps/mobile/apps/staff/pubspec.yaml index 3f8491e4..21c19091 100644 --- a/apps/mobile/apps/staff/pubspec.yaml +++ b/apps/mobile/apps/staff/pubspec.yaml @@ -1,7 +1,7 @@ name: krowwithus_staff description: "KROW Staff Application" publish_to: 'none' -version: 0.0.1-IlianaStaffM4 +version: 0.0.1-m4 resolution: workspace environment: diff --git a/docs/RELEASE/APK_SIGNING_IMPLEMENTATION_SUMMARY.md b/docs/RELEASE/APK_SIGNING_IMPLEMENTATION_SUMMARY.md new file mode 100644 index 00000000..5aa49911 --- /dev/null +++ b/docs/RELEASE/APK_SIGNING_IMPLEMENTATION_SUMMARY.md @@ -0,0 +1,363 @@ +# APK Signing Implementation - Complete Summary + +**Status**: โœ… Implementation Complete | ๐ŸŸก Secrets Configuration Pending + +**Last Updated**: 2024 + +--- + +## ๐Ÿ“‹ What Was Implemented + +### 1. GitHub Actions Workflow Updates + +**File**: `.github/workflows/product-release.yml` + +**New Steps Added**: +1. **๐Ÿ” Setup APK Signing** (before build) + - Detects app (worker/client) and environment (dev/stage/prod) + - Decodes keystore from GitHub Secrets + - Sets CodeMagic-compatible environment variables + - Configures `CI=true` for build.gradle.kts detection + - Gracefully handles missing secrets with warnings + +2. **โœ… Verify APK Signature** (after build) + - Verifies APK is properly signed using `jarsigner` + - Displays certificate details + - Shows signer information + - Provides helpful warnings if unsigned + +**How It Works**: +```yaml +Setup Signing: + - Reads: ${{ secrets.WORKER_KEYSTORE_DEV_BASE64 }} + - Decodes to: /tmp/keystores/release.jks + - Sets env: CI=true, CM_KEYSTORE_PATH_STAFF=/tmp/keystores/release.jks + +Build APK: + - Runs: make mobile-staff-build PLATFORM=apk MODE=release + - build.gradle.kts detects CI=true + - Uses environment variables for signing + +Verify Signature: + - Checks with: jarsigner -verify app-release.apk + - Displays certificate info +``` + +### 2. Documentation Created + +**Files Created**: + +| File | Purpose | Lines | +|------|---------|-------| +| [docs/RELEASE/APK_SIGNING_SETUP.md](../../docs/RELEASE/APK_SIGNING_SETUP.md) | Complete setup guide | 300+ | +| [docs/RELEASE/GITHUB_SECRETS_CHECKLIST.md](../../docs/RELEASE/GITHUB_SECRETS_CHECKLIST.md) | Quick reference checklist | 120+ | +| [.github/scripts/setup-github-secrets.sh](../../.github/scripts/setup-github-secrets.sh) | Helper script | 200+ | + +### 3. Scripts Created + +**File**: `.github/scripts/setup-github-secrets.sh` + +**Purpose**: Interactive helper to: +- Show which secrets are needed +- Generate base64 from existing keystores +- Display keytool information +- Provide copy-paste commands + +**Usage**: +```bash +./.github/scripts/setup-github-secrets.sh +``` + +--- + +## ๐Ÿ”‘ GitHub Secrets Required + +**Total: 24 Secrets** (6 keystores ร— 4 properties each) + +### Secret Naming Pattern: +``` +{APP}_KEYSTORE_{ENV}_BASE64 +{APP}_KEYSTORE_PASSWORD_{ENV} +{APP}_KEY_ALIAS_{ENV} +{APP}_KEY_PASSWORD_{ENV} +``` + +Where: +- `{APP}` = `WORKER` or `CLIENT` +- `{ENV}` = `DEV`, `STAGING`, or `PROD` + +### Full List: + +**Worker Mobile (12 secrets)**: +- `WORKER_KEYSTORE_DEV_BASE64`, `WORKER_KEYSTORE_PASSWORD_DEV`, `WORKER_KEY_ALIAS_DEV`, `WORKER_KEY_PASSWORD_DEV` +- `WORKER_KEYSTORE_STAGING_BASE64`, `WORKER_KEYSTORE_PASSWORD_STAGING`, `WORKER_KEY_ALIAS_STAGING`, `WORKER_KEY_PASSWORD_STAGING` +- `WORKER_KEYSTORE_PROD_BASE64`, `WORKER_KEYSTORE_PASSWORD_PROD`, `WORKER_KEY_ALIAS_PROD`, `WORKER_KEY_PASSWORD_PROD` + +**Client Mobile (12 secrets)**: +- `CLIENT_KEYSTORE_DEV_BASE64`, `CLIENT_KEYSTORE_PASSWORD_DEV`, `CLIENT_KEY_ALIAS_DEV`, `CLIENT_KEY_PASSWORD_DEV` +- `CLIENT_KEYSTORE_STAGING_BASE64`, `CLIENT_KEYSTORE_PASSWORD_STAGING`, `CLIENT_KEY_ALIAS_STAGING`, `CLIENT_KEY_PASSWORD_STAGING` +- `CLIENT_KEYSTORE_PROD_BASE64`, `CLIENT_KEYSTORE_PASSWORD_PROD`, `CLIENT_KEY_ALIAS_PROD`, `CLIENT_KEY_PASSWORD_PROD` + +--- + +## ๐Ÿš€ How to Configure + +### Step 1: Prepare Dev Keystores + +Dev keystores are already in the repository: +- Worker: `apps/mobile/apps/staff/android/app/krow_with_us_staff_dev.jks` +- Client: `apps/mobile/apps/client/android/app/krow_with_us_client_dev.jks` + +Generate base64: +```bash +# Worker Dev +base64 -i apps/mobile/apps/staff/android/app/krow_with_us_staff_dev.jks + +# Client Dev +base64 -i apps/mobile/apps/client/android/app/krow_with_us_client_dev.jks +``` + +### Step 2: Retrieve Staging/Prod Keystores + +**Option A**: From CodeMagic +1. Go to CodeMagic โ†’ Team Settings โ†’ Code signing identities +2. Download keystores: `krow_staff_staging.jks`, `krow_staff_prod.jks`, etc. +3. Generate base64 for each + +**Option B**: From Secure Storage +1. Retrieve from your organization's key management system +2. Generate base64 for each + +### Step 3: Add to GitHub + +1. Go to: **Repository โ†’ Settings โ†’ Secrets and variables โ†’ Actions** +2. Click: **New repository secret** +3. Add all 24 secrets (use checklist: [GITHUB_SECRETS_CHECKLIST.md](../../docs/RELEASE/GITHUB_SECRETS_CHECKLIST.md)) + +### Step 4: Test the Workflow + +```bash +# Test with dev environment first +# Go to: Actions โ†’ Product Release โ†’ Run workflow +# Select: +# - App: worker-mobile-app +# - Environment: dev +# - Version type: patch +# - Create GitHub Release: true +``` + +**Expected Output**: +``` +๐Ÿ” Setting up Android signing for worker-mobile-app in dev environment... +โœ… Keystore decoded successfully +๐Ÿ“ฆ Keystore size: 3.2K +โœ… Signing environment configured for STAFF (dev environment) +๐Ÿ”‘ Using key alias: krow_staff_dev + +๐Ÿ“ฑ Building Staff (Worker) APK... +โœ… APK built successfully + +๐Ÿ” Verifying APK signature... +โœ… APK is properly signed! +๐Ÿ“œ Certificate Details: [shows cert info] +``` + +--- + +## ๐Ÿ”’ Security Considerations + +### โœ… Safe Practices + +1. **Dev keystores in repo**: Acceptable for development + - Committed: `krow_with_us_staff_dev.jks`, `krow_with_us_client_dev.jks` + - Password: `krowwithus` (public knowledge) + +2. **Staging/Prod keystores**: ONLY in GitHub Secrets + - Never commit to repository + - Encrypted at rest by GitHub + - Only accessible in workflow runs + +3. **Keystore cleanup**: Workflow stores in `${{ runner.temp }}` + - Automatically deleted after job completes + - Not persisted in artifacts or logs + +### โš ๏ธ Important Notes + +1. **Same keystores as CodeMagic**: Use identical keystores to ensure app updates work +2. **Signature consistency**: Apps signed with different keystores cannot update each other +3. **Key rotation**: Document process for rotating production keys +4. **Backup keystores**: Keep secure backups - lost keystores = can't update app + +--- + +## ๐Ÿงช Testing Checklist + +Before using in production: + +- [ ] Configure all 24 GitHub Secrets +- [ ] Run workflow with `dev` environment +- [ ] Download APK artifact +- [ ] Verify signature: `jarsigner -verify -verbose app.apk` +- [ ] Install APK on Android device +- [ ] Launch app and verify functionality +- [ ] Compare signature fingerprints with CodeMagic builds +- [ ] Test `stage` environment +- [ ] Test `prod` environment (after full validation) + +--- + +## ๐Ÿ“Š Architecture Overview + +``` +โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” +โ”‚ GitHub Actions Workflow: product-release.yml โ”‚ +โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค +โ”‚ โ”‚ +โ”‚ 1. Validate & Create Release โ”‚ +โ”‚ โ””โ”€> Extract version from pubspec.yaml โ”‚ +โ”‚ โ””โ”€> Create Git tag โ”‚ +โ”‚ โ””โ”€> Create GitHub Release โ”‚ +โ”‚ โ”‚ +โ”‚ 2. Build Mobile Artifacts โ”‚ +โ”‚ โ”‚ โ”‚ +โ”‚ โ”œโ”€> Setup Node.js + Firebase CLI โ”‚ +โ”‚ โ”œโ”€> Setup Java 17 โ”‚ +โ”‚ โ”œโ”€> Setup Flutter 3.24.5 โ”‚ +โ”‚ โ”œโ”€> Install Melos โ”‚ +โ”‚ โ”œโ”€> Install Dependencies โ”‚ +โ”‚ โ”‚ โ”‚ +โ”‚ โ”œโ”€> ๐Ÿ” Setup APK Signing (NEW) โ”‚ +โ”‚ โ”‚ โ”œโ”€> Detect app (worker/client) โ”‚ +โ”‚ โ”‚ โ”œโ”€> Detect environment (dev/stage/prod) โ”‚ +โ”‚ โ”‚ โ”œโ”€> Read GitHub Secret: โ”‚ +โ”‚ โ”‚ โ”‚ {APP}_KEYSTORE_{ENV}_BASE64 โ”‚ +โ”‚ โ”‚ โ”œโ”€> Decode base64 โ†’ .jks file โ”‚ +โ”‚ โ”‚ โ”œโ”€> Set environment variables: โ”‚ +โ”‚ โ”‚ โ”‚ - CI=true โ”‚ +โ”‚ โ”‚ โ”‚ - CM_KEYSTORE_PATH_STAFF=/tmp/keystore.jks โ”‚ +โ”‚ โ”‚ โ”‚ - CM_KEYSTORE_PASSWORD_STAFF=*** โ”‚ +โ”‚ โ”‚ โ”‚ - CM_KEY_ALIAS_STAFF=krow_staff_dev โ”‚ +โ”‚ โ”‚ โ”‚ - CM_KEY_PASSWORD_STAFF=*** โ”‚ +โ”‚ โ”‚ โ””โ”€> โœ… Ready for signed build โ”‚ +โ”‚ โ”‚ โ”‚ +โ”‚ โ”œโ”€> ๐Ÿ—๏ธ Build APK โ”‚ +โ”‚ โ”‚ โ””โ”€> make mobile-staff-build PLATFORM=apk โ”‚ +โ”‚ โ”‚ โ””โ”€> Flutter build detects CI=true โ”‚ +โ”‚ โ”‚ โ””โ”€> build.gradle.kts uses env vars โ”‚ +โ”‚ โ”‚ โ””โ”€> Signs APK with keystore โ”‚ +โ”‚ โ”‚ โ”‚ +โ”‚ โ”œโ”€> โœ… Verify APK Signature (NEW) โ”‚ +โ”‚ โ”‚ โ”œโ”€> jarsigner -verify app-release.apk โ”‚ +โ”‚ โ”‚ โ”œโ”€> Show certificate details โ”‚ +โ”‚ โ”‚ โ””โ”€> Confirm signing successful โ”‚ +โ”‚ โ”‚ โ”‚ +โ”‚ โ”œโ”€> ๐Ÿ“ค Upload APK as Artifact โ”‚ +โ”‚ โ”‚ โ””โ”€> 30-day retention in GitHub Actions โ”‚ +โ”‚ โ”‚ โ”‚ +โ”‚ โ””โ”€> ๐Ÿ“ฆ Attach APK to GitHub Release โ”‚ +โ”‚ โ””โ”€> krow-withus-worker-mobile-dev-v0.1.0.apk โ”‚ +โ”‚ โ”‚ +โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ + +โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” +โ”‚ Build Configuration: build.gradle.kts โ”‚ +โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค +โ”‚ โ”‚ +โ”‚ signingConfigs { โ”‚ +โ”‚ create("release") { โ”‚ +โ”‚ if (System.getenv()["CI"] == "true") { โ”‚ +โ”‚ // โœ… GitHub Actions / CodeMagic โ”‚ +โ”‚ storeFile = file( โ”‚ +โ”‚ System.getenv()["CM_KEYSTORE_PATH_STAFF"] โ”‚ +โ”‚ ) โ”‚ +โ”‚ storePassword = โ”‚ +โ”‚ System.getenv()["CM_KEYSTORE_PASSWORD_*"] โ”‚ +โ”‚ keyAlias = โ”‚ +โ”‚ System.getenv()["CM_KEY_ALIAS_*"] โ”‚ +โ”‚ keyPassword = โ”‚ +โ”‚ System.getenv()["CM_KEY_PASSWORD_*"] โ”‚ +โ”‚ } else { โ”‚ +โ”‚ // Local Development โ”‚ +โ”‚ use key.properties file โ”‚ +โ”‚ } โ”‚ +โ”‚ } โ”‚ +โ”‚ } โ”‚ +โ”‚ โ”‚ +โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ +``` + +--- + +## ๐Ÿ“– Documentation Index + +1. **[APK_SIGNING_SETUP.md](../../docs/RELEASE/APK_SIGNING_SETUP.md)** + - Complete setup guide with all details + - Security best practices + - Troubleshooting guide + - Keystore management commands + +2. **[GITHUB_SECRETS_CHECKLIST.md](../../docs/RELEASE/GITHUB_SECRETS_CHECKLIST.md)** + - Quick reference for all 24 secrets + - Copy-paste checklist + - Dev environment values + +3. **[setup-mobile-github-secrets.sh](../../.github/scripts/setup-mobile-github-secrets.sh)** + - Interactive helper script + - Shows existing keystores + - Generates base64 commands + - Displays keytool info + +4. **[product-release.yml](../../.github/workflows/product-release.yml)** + - Updated workflow with signing + - Lines 198-294: Setup APK Signing + - Lines 330-364: Verify APK Signature + +--- + +## โœ… Next Steps + +### Immediate (Required for Signed APKs) +1. **Configure GitHub Secrets** (30 minutes) + - Start with dev environment (test first) + - Use helper script: `.github/scripts/setup-mobile-github-secrets.sh` + - Follow checklist: `docs/RELEASE/GITHUB_SECRETS_CHECKLIST.md` + +2. **Test Dev Signing** (15 minutes) + - Run workflow with dev environment + - Download APK and verify signature + - Install on device and test + +3. **Configure Staging/Prod** (30 minutes) + - Retrieve keystores from CodeMagic/secure storage + - Add to GitHub Secrets + - Test each environment + +### Future Enhancements (Optional) +- [ ] Add AAB (Android App Bundle) support for Play Store +- [ ] Implement iOS signing for IPA files +- [ ] Add automated Play Store upload +- [ ] Set up GitHub Environments with protection rules +- [ ] Add Slack notifications for releases + +--- + +## ๐Ÿ†˜ Support + +If you encounter issues: + +1. Check workflow logs for signing step output +2. Verify GitHub Secrets are configured correctly +3. Run helper script: `.github/scripts/setup-mobile-github-secrets.sh` +4. Review: `docs/RELEASE/APK_SIGNING_SETUP.md` โ†’ Troubleshooting section + +**Common Issues**: +- "Keystore not found" โ†’ Secret not configured or wrong name +- "Wrong password" โ†’ Secret value doesn't match actual keystore +- APK unsigned โ†’ CI=true not set or build.gradle.kts issue +- App won't install over existing โ†’ Different keystore used + +--- + +**Implementation Date**: 2024 +**Implemented By**: GitHub Copilot (Claude Sonnet 4.5) +**Status**: โœ… Code Complete | ๐ŸŸก Awaiting Secrets Configuration diff --git a/docs/RELEASE/APK_SIGNING_SETUP.md b/docs/RELEASE/APK_SIGNING_SETUP.md new file mode 100644 index 00000000..6149937b --- /dev/null +++ b/docs/RELEASE/APK_SIGNING_SETUP.md @@ -0,0 +1,282 @@ +# APK Signing Setup for GitHub Actions + +**For Worker Mobile & Client Mobile Apps** + +--- + +## ๐Ÿ“‹ Overview + +This document explains how to set up APK signing for automated builds in GitHub Actions. The same keystore files used in CodeMagic will be used here. + +--- + +## ๐Ÿ”‘ Understanding App Signing + +### Why Sign APKs? + +- **Required by Google Play**: All Android apps must be signed before distribution +- **App Identity**: The signature identifies your app across updates +- **Security**: Ensures the APK hasn't been tampered with + +### Keystore Files + +Each app and environment combination has its own keystore: + +**Worker Mobile (Staff App):** +- `krow_staff_dev.jks` - Development builds +- `krow_staff_staging.jks` - Staging builds +- `krow_staff_prod.jks` - Production builds + +**Client Mobile:** +- `krow_client_dev.jks` - Development builds +- `krow_client_staging.jks` - Staging builds +- `krow_client_prod.jks` - Production builds + +### Current State + +- โœ… **Dev keystores** are committed to the repository (in `apps/mobile/apps/*/android/app/`) +- โš ๏ธ **Staging/Prod keystores** are stored securely in CodeMagic (NOT in repo) + +--- + +## ๐Ÿ” GitHub Secrets Setup + +### Step 1: Export Keystores as Base64 + +For staging and production keystores (stored in CodeMagic), you'll need to: + +```bash +# On your local machine with access to the keystore files: + +# For Worker Mobile - Staging +base64 -i krow_staff_staging.jks -o krow_staff_staging.jks.base64 + +# For Worker Mobile - Production +base64 -i krow_staff_prod.jks -o krow_staff_prod.jks.base64 + +# For Client Mobile - Staging +base64 -i krow_client_staging.jks -o krow_client_staging.jks.base64 + +# For Client Mobile - Production +base64 -i krow_client_prod.jks -o krow_client_prod.jks.base64 +``` + +### Step 2: Create GitHub Secrets + +Go to: **GitHub Repository โ†’ Settings โ†’ Secrets and variables โ†’ Actions โ†’ New repository secret** + +Create the following secrets: + +#### Worker Mobile (Staff App) Secrets + +| Secret Name | Value | Environment | +|-------------|-------|-------------| +| `WORKER_KEYSTORE_DEV_BASE64` | (base64 of dev keystore) | dev | +| `WORKER_KEYSTORE_STAGING_BASE64` | (base64 of staging keystore) | stage | +| `WORKER_KEYSTORE_PROD_BASE64` | (base64 of prod keystore) | prod | +| `WORKER_KEYSTORE_PASSWORD_DEV` | `krowwithus` | dev | +| `WORKER_KEYSTORE_PASSWORD_STAGING` | (actual staging password) | stage | +| `WORKER_KEYSTORE_PASSWORD_PROD` | (actual prod password) | prod | +| `WORKER_KEY_ALIAS_DEV` | `krow_staff_dev` | dev | +| `WORKER_KEY_ALIAS_STAGING` | (actual staging alias) | stage | +| `WORKER_KEY_ALIAS_PROD` | (actual prod alias) | prod | +| `WORKER_KEY_PASSWORD_DEV` | `krowwithus` | dev | +| `WORKER_KEY_PASSWORD_STAGING` | (actual staging key password) | stage | +| `WORKER_KEY_PASSWORD_PROD` | (actual prod key password) | prod | + +#### Client Mobile Secrets + +| Secret Name | Value | Environment | +|-------------|-------|-------------| +| `CLIENT_KEYSTORE_DEV_BASE64` | (base64 of dev keystore) | dev | +| `CLIENT_KEYSTORE_STAGING_BASE64` | (base64 of staging keystore) | stage | +| `CLIENT_KEYSTORE_PROD_BASE64` | (base64 of prod keystore) | prod | +| `CLIENT_KEYSTORE_PASSWORD_DEV` | `krowwithus` | dev | +| `CLIENT_KEYSTORE_PASSWORD_STAGING` | (actual staging password) | stage | +| `CLIENT_KEYSTORE_PASSWORD_PROD` | (actual prod password) | prod | +| `CLIENT_KEY_ALIAS_DEV` | `krow_client_dev` | dev | +| `CLIENT_KEY_ALIAS_STAGING` | (actual staging alias) | stage | +| `CLIENT_KEY_ALIAS_PROD` | (actual prod alias) | prod | +| `CLIENT_KEY_PASSWORD_DEV` | `krowwithus` | dev | +| `CLIENT_KEY_PASSWORD_STAGING` | (actual staging key password) | stage | +| `CLIENT_KEY_PASSWORD_PROD` | (actual prod key password) | prod | + +--- + +## โš™๏ธ How It Works in GitHub Actions + +### Build Configuration Detection + +The `build.gradle.kts` files check for `CI=true` environment variable: + +```kotlin +signingConfigs { + create("release") { + if (System.getenv()["CI"] == "true") { + // CI environment (CodeMagic or GitHub Actions) + storeFile = file(System.getenv()["CM_KEYSTORE_PATH_STAFF"] ?: "") + storePassword = System.getenv()["CM_KEYSTORE_PASSWORD_STAFF"] + keyAlias = System.getenv()["CM_KEY_ALIAS_STAFF"] + keyPassword = System.getenv()["CM_KEY_PASSWORD_STAFF"] + } else { + // Local development (uses key.properties) + keyAlias = keystoreProperties["keyAlias"] as String? + keyPassword = keystoreProperties["keyPassword"] as String? + storeFile = keystoreProperties["storeFile"]?.let { file(it) } + storePassword = keystoreProperties["storePassword"] as String? + } + } +} +``` + +### GitHub Actions Workflow Steps + +1. **Decode Keystore**: Convert base64 secret back to `.jks` file +2. **Set Environment Variables**: Provide the same env vars CodeMagic uses +3. **Build APK**: Flutter build automatically uses the signing config +4. **Verify Signature**: Optionally verify the APK is signed correctly + +--- + +## ๐Ÿš€ Usage + +### For Development Builds + +Dev keystores are already in the repo, so GitHub Actions will automatically use them: + +```bash +# No special setup needed for dev builds +# They use committed keystores: krow_with_us_staff_dev.jks +``` + +### For Staging/Production Builds + +Once GitHub Secrets are configured (Step 2 above), the workflow will: + +1. Detect the environment (dev/stage/prod) +2. Use the appropriate keystore secret +3. Decode it before building +4. Sign the APK automatically + +--- + +## โœ… Verification + +### Check APK Signature + +After building, verify the APK is signed: + +```bash +# Using keytool (part of Java JDK) +keytool -printcert -jarfile app-release.apk + +# Expected output should show certificate info with your key alias +``` + +### Check Build Logs + +In GitHub Actions, look for: +``` +โœ… Keystore decoded successfully +โœ… APK signed with: krow_staff_prod +โœ… APK built successfully: /path/to/app-release.apk +``` + +--- + +## ๐Ÿ”’ Security Best Practices + +### DO: +- โœ… Store production keystores ONLY in GitHub Secrets (encrypted) +- โœ… Use different keystores for dev/staging/prod +- โœ… Rotate passwords periodically +- โœ… Limit access to repository secrets (use environment protection rules) +- โœ… Keep keystore files backed up securely offline + +### DON'T: +- โŒ Never commit staging/production keystores to Git +- โŒ Never share keystore passwords in plain text +- โŒ Never use production keystores for development +- โŒ Never commit `.jks` files for staging/prod + +--- + +## ๐Ÿ“ Keystore Management Commands + +### Generate New Keystore + +```bash +keytool -genkey -v \ + -keystore krow_staff_prod.jks \ + -alias krow_staff_prod \ + -keyalg RSA \ + -keysize 2048 \ + -validity 10000 \ + -storetype JKS +``` + +### View Keystore Info + +```bash +keytool -list -v -keystore krow_staff_prod.jks +``` + +### Get SHA-1 and SHA-256 Fingerprints + +```bash +keytool -list -v -keystore krow_staff_prod.jks -alias krow_staff_prod +``` + +These fingerprints are needed for: +- Firebase project configuration +- Google Maps API key restrictions +- Google Play Console app signing + +--- + +## ๐Ÿ†˜ Troubleshooting + +### "keystore not found" Error + +**Problem**: GitHub Actions can't find the decoded keystore +**Solution**: Check the decode step in the workflow creates the file in the correct location + +### "wrong password" Error + +**Problem**: Keystore password doesn't match +**Solution**: Verify the GitHub Secret value matches the actual keystore password + +### APK Not Signed + +**Problem**: APK builds but isn't signed +**Solution**: Ensure `CI=true` is set before building + +### Certificate Mismatch + +**Problem**: "App not installed" when updating +**Solution**: You're using a different keystore than previous builds. Use the same keystore for all versions. + +--- + +## ๐Ÿ“š Related Documentation + +- [Product Release Workflow](./MOBILE_RELEASE_PLAN.md) +- [Hotfix Process](./HOTFIX_PROCESS.md) +- [CodeMagic Configuration](/codemagic.yaml) +- [Android App Signing (Google Docs)](https://developer.android.com/studio/publish/app-signing) + +--- + +## ๐Ÿ”„ Migration from CodeMagic + +If you want to use GitHub Actions instead of CodeMagic: + +1. Export all keystores from CodeMagic +2. Convert to base64 (as shown above) +3. Add to GitHub Secrets +4. Test with a dev build first +5. Verify signatures match previous releases +6. Deploy staging build for testing +7. Only then use for production + +**Important**: Make sure the GitHub Actions builds produce the SAME signature as CodeMagic builds, otherwise app updates will fail! diff --git a/docs/RELEASE/GITHUB_SECRETS_CHECKLIST.md b/docs/RELEASE/GITHUB_SECRETS_CHECKLIST.md new file mode 100644 index 00000000..b04eb3ad --- /dev/null +++ b/docs/RELEASE/GITHUB_SECRETS_CHECKLIST.md @@ -0,0 +1,115 @@ +# GitHub Secrets Checklist for APK Signing + +**Quick reference for repository secret configuration** + +๐Ÿ“ **Configure at**: Repository Settings โ†’ Secrets and variables โ†’ Actions + +--- + +## โœ… Worker Mobile (Staff App) - 12 Secrets + +### Dev Environment +- [ ] `WORKER_KEYSTORE_DEV_BASE64` +- [ ] `WORKER_KEYSTORE_PASSWORD_DEV` +- [ ] `WORKER_KEY_ALIAS_DEV` +- [ ] `WORKER_KEY_PASSWORD_DEV` + +### Staging Environment +- [ ] `WORKER_KEYSTORE_STAGING_BASE64` +- [ ] `WORKER_KEYSTORE_PASSWORD_STAGING` +- [ ] `WORKER_KEY_ALIAS_STAGING` +- [ ] `WORKER_KEY_PASSWORD_STAGING` + +### Production Environment +- [ ] `WORKER_KEYSTORE_PROD_BASE64` +- [ ] `WORKER_KEYSTORE_PASSWORD_PROD` +- [ ] `WORKER_KEY_ALIAS_PROD` +- [ ] `WORKER_KEY_PASSWORD_PROD` + +--- + +## โœ… Client Mobile - 12 Secrets + +### Dev Environment +- [ ] `CLIENT_KEYSTORE_DEV_BASE64` +- [ ] `CLIENT_KEYSTORE_PASSWORD_DEV` +- [ ] `CLIENT_KEY_ALIAS_DEV` +- [ ] `CLIENT_KEY_PASSWORD_DEV` + +### Staging Environment +- [ ] `CLIENT_KEYSTORE_STAGING_BASE64` +- [ ] `CLIENT_KEYSTORE_PASSWORD_STAGING` +- [ ] `CLIENT_KEY_ALIAS_STAGING` +- [ ] `CLIENT_KEY_PASSWORD_STAGING` + +### Production Environment +- [ ] `CLIENT_KEYSTORE_PROD_BASE64` +- [ ] `CLIENT_KEYSTORE_PASSWORD_PROD` +- [ ] `CLIENT_KEY_ALIAS_PROD` +- [ ] `CLIENT_KEY_PASSWORD_PROD` + +--- + +## ๐Ÿ“ฆ Total: 24 Secrets + +**Status**: โฌœ Not Started | ๐ŸŸก In Progress | โœ… Complete + +--- + +## ๐Ÿ”ง Quick Setup Commands + +### Generate base64 for existing keystores: + +```bash +# Worker Mobile Dev (already in repo) +base64 -i apps/mobile/apps/staff/android/app/krow_with_us_staff_dev.jks + +# Client Mobile Dev (already in repo) +base64 -i apps/mobile/apps/client/android/app/krow_with_us_client_dev.jks + +# For staging/prod keystores (retrieve from secure storage first): +base64 -i /path/to/krow_staff_staging.jks +base64 -i /path/to/krow_staff_prod.jks +base64 -i /path/to/krow_client_staging.jks +base64 -i /path/to/krow_client_prod.jks +``` + +### Or use the helper script: + +```bash +.github/scripts/setup-mobile-github-secrets.sh +``` + +--- + +## ๐Ÿ“‹ Dev Environment Values (Public - Already in Repo) + +**Worker Mobile:** +- Password: `krowwithus` +- Alias: `krow_staff_dev` +- Key Password: `krowwithus` +- Keystore: `apps/mobile/apps/staff/android/app/krow_with_us_staff_dev.jks` + +**Client Mobile:** +- Password: `krowwithus` +- Alias: `krow_client_dev` +- Key Password: `krowwithus` +- Keystore: `apps/mobile/apps/client/android/app/krow_with_us_client_dev.jks` + +--- + +## ๐Ÿšจ Important Notes + +1. **Staging/Production keystores** should NEVER be committed to the repository +2. Retrieve staging/prod keystores from: + - CodeMagic Team Settings โ†’ Code signing identities + - Or your organization's secure key management system +3. Keep keystore passwords in a password manager +4. Test with **dev environment first** before configuring staging/prod + +--- + +## ๐Ÿ“š Related Documentation + +- [Complete Setup Guide](./APK_SIGNING_SETUP.md) +- [Release Workflow](./MOBILE_RELEASE_PLAN.md) diff --git a/docs/RELEASE/HOTFIX_PROCESS.md b/docs/RELEASE/HOTFIX_PROCESS.md new file mode 100644 index 00000000..313b9be6 --- /dev/null +++ b/docs/RELEASE/HOTFIX_PROCESS.md @@ -0,0 +1,343 @@ +# Hotfix Process + +**For Emergency Production Fixes** + +--- + +## ๐Ÿšจ When to Hotfix + +Use hotfix when: +- โœ… Critical bug in production affecting users +- โœ… Data loss or security vulnerability +- โœ… Service unavailable or major feature broken +- โœ… Customer-blocking issue + +**Don't use hotfix for:** +- โŒ Minor bugs (can wait for next release) +- โŒ Feature requests +- โŒ Nice-to-have improvements +- โŒ Styling issues + +--- + +## ๐Ÿ”„ Hotfix Process + +### Step 1: Assess & Declare Emergency + +``` +Issue: [Brief description] +Severity: CRITICAL / HIGH / MEDIUM +Product: [Staff Mobile / Client Mobile / Web / Backend] +Environment: Production +Impact: [How many users affected] +``` + +Once severity confirmed โ†’ Start hotfix immediately. + +--- + +### Step 2: Create Hotfix Branch + +```bash +# From production tag +git checkout -b hotfix/krow-withus-worker-mobile-v0.1.1 \ + krow-withus-worker-mobile/prod-v0.1.0 + +# Verify you're on the right tag +git log -1 --oneline +``` + +**Format**: `hotfix/-v` + +--- + +### Step 3: Fix the Bug + +```bash +# Make your fix +# Edit files, test locally + +# Commit with clear message +git commit -m "fix: [issue description] + +HOTFIX for production +Issue: [what happened] +Solution: [what was fixed] +Tested: [how was it tested locally]" +``` + +**Keep it minimal:** +- Only fix the specific bug +- Don't refactor or optimize +- Don't add new features + +--- + +### Step 4: Update Version + +Update PATCH version only (0.1.0 โ†’ 0.1.1): + +**For Mobile** (`apps/mobile/apps/*/pubspec.yaml`): +```yaml +# Old +version: 0.1.0+5 + +# New +version: 0.1.1+6 # Only PATCH changed +``` + +**For Web** (`apps/web/package.json`): +```json +"version": "0.1.1" +``` + +**For Backend** (`backend/*/package.json`): +```json +"version": "0.1.1" +``` + +--- + +### Step 5: Update CHANGELOG + +Add entry to **top** of appropriate CHANGELOG: + +```markdown +| 2026-03-05 | 0.1.1 | HOTFIX: [Issue fixed] | + +(previous entries below...) +``` + +--- + +### Step 6: Code Review (Expedited) + +```bash +# Push hotfix branch +git push origin hotfix/krow-withus-worker-mobile-v0.1.1 + +# Create PR on GitHub with URGENT label +gh pr create --title "HOTFIX: [Issue description]" \ + --body "**URGENT PRODUCTION FIX** + +Issue: [What was broken] +Impact: [Users affected] +Solution: [What was fixed] +Testing: [Local verification]" +``` + +**Get approval within 15 minutes if possible.** + +--- + +### Step 7: Merge to Main + +```bash +# Review complete - merge +git checkout main +git pull origin main +git merge --ff-only hotfix/krow-withus-worker-mobile-v0.1.1 +git push origin main +``` + +--- + +### Step 8: Create Production Tag + +```bash +# Create tag from main +git tag -a krow-withus-worker-mobile/prod-v0.1.1 \ + -m "HOTFIX: [Issue fixed]" + +git push origin krow-withus-worker-mobile/prod-v0.1.1 +``` + +--- + +### Step 9: Deploy to Production + +```bash +# Follow your deployment procedure +# Higher priority than normal releases + +./scripts/deploy-mobile-production.sh krow-withus-worker-mobile/prod-v0.1.1 +``` + +**Deployment time**: Within 30 minutes of approval + +--- + +### Step 10: Verify & Monitor + +```bash +# Smoke tests +- App launches +- Core features work +- No new errors + +# Monitor for 2 hours +- Watch error logs +- Check user reports +- Verify fix worked +``` + +--- + +### Step 11: Communicate + +**Immediately after deployment:** + +```markdown +๐Ÿšจ PRODUCTION HOTFIX DEPLOYED + +Product: Worker Mobile +Version: 0.1.1 +Issue: [Fixed issue] +Impact: [Resolved for X users] +Status: โœ… Deployed & verified + +No user action required. +Service restored to normal. +``` + +**24 hours later:** + +```markdown +โœ… HOTFIX STATUS UPDATE + +Production hotfix v0.1.1 deployed 24 hours ago. +Zero errors reported post-deployment. +System stable. + +Thank you for your patience! +``` + +--- + +## โฑ๏ธ Timeline + +``` +T-0: Issue detected & reported +T+5min: Severity assessed, hotfix branch created +T+15: Fix implemented, code review started +T+30: Approved & merged, tag created +T+45: Deployed to production +T+60: Smoke tests pass, monitoring enabled +T+120: Declare emergency resolved, communicate +T+1day: Follow-up communication +``` + +**Total time: 2-4 hours from detection to resolution** + +--- + +## ๐Ÿšซ Common Mistakes to Avoid + +โŒ **Don't**: +- Skip code review (even in emergency) +- Add multiple unrelated fixes in one hotfix +- Forget to update version number +- Forget CHANGELOG entry +- Deploy without testing +- Forget to communicate with users + +โœ… **Do**: +- Keep hotfix minimal and focused +- Test every fix locally first +- Get at least one approval +- Update all version files +- Deploy immediately after approval +- Monitor actively for 2+ hours + +--- + +## ๐Ÿ“‹ Hotfix Checklist + +Copy for each emergency: + +``` +Hotfix: [Product] v[Old Version] โ†’ v[New Version] + +โ–ก Severity assessed & documented +โ–ก Branch created from production tag +โ–ก Bug fixed & tested locally +โ–ก Version number updated (PATCH only) +โ–ก CHANGELOG entry added +โ–ก Commit message clear +โ–ก Code review requested (marked URGENT) +โ–ก Approval obtained +โ–ก Merged to main +โ–ก Production tag created +โ–ก Tag pushed to remote +โ–ก Deployed to production +โ–ก Smoke tests passed +โ–ก Error logs monitored (2+ hours) +โ–ก Users notified +โ–ก GitHub Release created +โ–ก Incident documented + +Total Time: ___ minutes +``` + +--- + +## ๐Ÿ” Post-Incident + +After emergency is resolved: + +1. **Document what happened** + - Root cause analysis + - Why it wasn't caught before + - What testing was missed + +2. **Schedule postmortem** (within 24 hours) + - Review what went wrong + - Discuss prevention + - Update processes if needed + +3. **Plan prevention** + - Add test coverage + - Update CI/CD checks + - Improve monitoring + +4. **Communicate findings** + - Share with team + - Update documentation + - Prevent recurrence + +--- + +## ๐Ÿ“ž Emergency Contacts + +When issue detected: + +1. **Notify**: + - Release Engineer + - DevOps + - Product Owner + - Affected Team + +2. **Communication Channel**: + - Slack: #emergency-releases + - Time-sensitive decisions on call + +3. **Decision Maker**: + - Product Owner approves rollback vs hotfix + - Release Engineer executes + - DevOps monitors infrastructure + +--- + +## ๐Ÿ”— Related + +- [OVERALL_RELEASE_PLAN.md](./OVERALL_RELEASE_PLAN.md) - Main release strategy +- [MOBILE_RELEASE_PLAN.md](./MOBILE_RELEASE_PLAN.md) - Mobile-specific process +- [../../CHANGELOG.md](../../CHANGELOG.md) - Version history + +--- + +**Last Updated**: 2026-03-05 +**Severity Levels**: +- ๐Ÿ”ด CRITICAL: Service down, data loss, security (< 1 hour) +- ๐ŸŸ  HIGH: Major feature broken, workaround available (< 4 hours) +- ๐ŸŸก MEDIUM: Minor feature affected (next release OK) diff --git a/docs/RELEASE/MOBILE_RELEASE_PLAN.md b/docs/RELEASE/MOBILE_RELEASE_PLAN.md new file mode 100644 index 00000000..c37dcc5b --- /dev/null +++ b/docs/RELEASE/MOBILE_RELEASE_PLAN.md @@ -0,0 +1,564 @@ +# Mobile App Release Plan + +**For Staff Mobile & Client Mobile Apps** + +--- + +## ๐Ÿ“ฑ Overview + +This document covers release procedures for: + +- **Staff Mobile App** (aka "Worker Mobile") - `krow-withus-worker-mobile` +- **Client Mobile App** - `krow-withus-client-mobile` + +Both apps: +- Built with Flutter +- Distributed to iOS & Android app stores +- Maintain independent versions +- Have independent CHANGELOGs +- Share backend infrastructure + +--- + +## ๐Ÿท๏ธ Tag & Release Naming + +### Tag Format + +``` +krow-withus--mobile/-v.. +``` + +### Examples + +**Staff Mobile (Worker Mobile)** +``` +krow-withus-worker-mobile/dev-v0.1.0 +krow-withus-worker-mobile/stage-v0.2.0 +krow-withus-worker-mobile/prod-v1.0.0 +krow-withus-worker-mobile/prod-v1.0.1-hotfix.1 +``` + +**Client Mobile** +``` +krow-withus-client-mobile/dev-v0.1.0 +krow-withus-client-mobile/stage-v0.2.0 +krow-withus-client-mobile/prod-v1.0.0 +``` + +### GitHub Release Names + +``` +Krow With Us - Worker Mobile - DEV - v0.1.0 +Krow With Us - Worker Mobile - STAGE - v0.2.0 +Krow With Us - Worker Mobile - PROD - v1.0.0 + +Krow With Us - Client Mobile - DEV - v0.1.0 +Krow With Us - Client Mobile - STAGE - v0.2.0 +Krow With Us - Client Mobile - PROD - v1.0.0 +``` + +--- + +## ๐Ÿ“ CHANGELOG Management + +### Location + +Each app has its own CHANGELOG in the `apps/mobile/` directory structure: + +``` +apps/mobile/ +โ”œโ”€โ”€ packages/ +โ”‚ โ”œโ”€โ”€ features/ +โ”‚ โ”‚ โ”œโ”€โ”€ staff/ +โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ authentication/CHANGELOG.md +โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ home/CHANGELOG.md +โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ payments/CHANGELOG.md +โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ shifts/CHANGELOG.md +โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ ... (other staff features) +โ”‚ โ”‚ โ””โ”€โ”€ client/ +โ”‚ โ”‚ โ”œโ”€โ”€ dashboard/CHANGELOG.md +โ”‚ โ”‚ โ”œโ”€โ”€ orders/CHANGELOG.md +โ”‚ โ”‚ โ””โ”€โ”€ ... (other client features) +โ”‚ โ””โ”€โ”€ ... (other packages) +โ”œโ”€โ”€ apps/ +โ”‚ โ”œโ”€โ”€ staff_app/CHANGELOG.md โ† Staff app root +โ”‚ โ””โ”€โ”€ client_app/CHANGELOG.md โ† Client app root +โ””โ”€โ”€ CHANGELOG.md โ† Consolidated (optional) +``` + +### App-Level CHANGELOG Format + +**File**: `apps/mobile/apps/staff_app/CHANGELOG.md` + +```markdown +# Staff Mobile App - Change Log + +## [0.2.0] - 2026-03-15 + +### Added +- Feature X implementation +- Feature Y enhancement +- New UI component Z + +### Fixed +- Bug fix for issue #123 +- Crash when loading payments + +### Changed +- Updated design system +- Improved performance + +### Deprecated +- Removed old API endpoint + +## [0.1.0] - 2026-03-01 + +### Added +- Initial release +- Authentication with phone & OTP +- Shift browsing and booking +- Clock in/out functionality +- Payment history view +``` + +### Consolidated CHANGELOG (Optional) + +**File**: `apps/mobile/CHANGELOG.md` (at root of mobile folder) + +High-level overview of both apps: + +```markdown +# Krow Workforce - Mobile Apps - Change Log + +## Staff Mobile v0.2.0 + Client Mobile v0.1.0 - 2026-03-15 + +### Staff Mobile v0.2.0 +- Feature improvements +- Bug fixes + +### Client Mobile v0.1.0 +- Initial release + +## Previous versions... +``` + +--- + +## ๐Ÿ“ Version Files + +### Staff Mobile App + +**Primary Version File**: `apps/mobile/apps/staff_app/pubspec.yaml` + +```yaml +name: staff_app +description: "Krow With Us - Staff App" + +# Version format: MAJOR.MINOR.PATCH+BUILD_NUMBER +version: 0.1.0+1 + +environment: + sdk: '>=3.10.0 <4.0.0' + flutter: '>=3.38.0 <4.0.0' +``` + +**Rules**: +- Update version before each release +- Bump build number (+1) every build +- SemVer only for version part (before +) + +### Client Mobile App + +**Primary Version File**: `apps/mobile/apps/client_app/pubspec.yaml` + +```yaml +name: client_app +description: "Krow With Us - Client App" + +version: 0.1.0+1 + +environment: + sdk: '>=3.10.0 <4.0.0' + flutter: '>=3.38.0 <4.0.0' +``` + +--- + +## ๐Ÿš€ Release Workflow + +### Step 1: Create Release Branch + +```bash +cd /Users/achintha/Documents/GitHub/krow-workforce + +# For Staff Mobile +git checkout -b release/staff-mobile-v0.2.0 + +# For Client Mobile +git checkout -b release/client-mobile-v0.2.0 +``` + +--- + +### Step 2: Update Version Numbers + +#### Staff Mobile Example (v0.1.0 โ†’ v0.2.0) + +**File**: `apps/mobile/apps/staff_app/pubspec.yaml` + +```yaml +# Old +version: 0.1.0+5 + +# New +version: 0.2.0+6 +``` + +#### Client Mobile Example (v0.1.0 โ†’ v0.2.0) + +**File**: `apps/mobile/apps/client_app/pubspec.yaml` + +```yaml +# Old +version: 0.1.0+3 + +# New +version: 0.2.0+4 +``` + +--- + +### Step 3: Update CHANGELOG + +**File**: `apps/mobile/apps/staff_app/CHANGELOG.md` + +Add entry at **top**: + +```markdown +# Staff Mobile App - Change Log + +## [0.2.0] - 2026-03-05 + +### Added +- New shift details page with profile gating +- Benefits overview section +- Auto-match functionality + +### Fixed +- Payment history display bug +- Clock-in location verification + +### Changed +- Updated design system components +- Improved shift booking flow + +## [0.1.0] - 2026-02-15 +... +``` + +--- + +### Step 4: Commit Changes + +```bash +cd /Users/achintha/Documents/GitHub/krow-workforce + +# Stage changes +git add apps/mobile/apps/staff_app/pubspec.yaml +git add apps/mobile/apps/staff_app/CHANGELOG.md + +# Commit +git commit -m "chore(staff-mobile): bump version to 0.2.0 + +- Updated pubspec.yaml version: 0.1.0 โ†’ 0.2.0 +- Updated build number: 5 โ†’ 6 +- Updated CHANGELOG.md with v0.2.0 changes" +``` + +--- + +### Step 5: Create Pull Request + +```bash +# Push release branch +git push origin release/staff-mobile-v0.2.0 + +# Create PR (GitHub CLI) +gh pr create \ + --title "Release: Staff Mobile v0.2.0" \ + --body "## Release: Staff Mobile v0.2.0 + +### Changes +- See CHANGELOG.md for full list + +### Testing +- [ ] All tests passing +- [ ] Manual testing complete +- [ ] CodeMagic build successful + +### Checklist +- [x] Version updated +- [x] CHANGELOG updated +- [x] Branch created from main +- [ ] Approved by team lead" +``` + +--- + +### Step 6: Merge to Main + +Once PR is approved: + +```bash +# Switch to main +git checkout main +git pull origin main + +# Merge (fast-forward only) +git merge --ff-only release/staff-mobile-v0.2.0 + +# Push to remote +git push origin main + +# Delete release branch +git push origin --delete release/staff-mobile-v0.2.0 +``` + +--- + +### Step 7: Create Git Tag + +```bash +# For DEV release +git tag -a krow-withus-worker-mobile/dev-v0.2.0 \ + -m "Staff Mobile v0.2.0 - Dev Release + +Features: +- Shift details improvements +- Benefits overview +- Auto-match functionality + +Testing: +- All unit tests passing +- Manual QA on dev environment" + +# For STAGE release +git tag -a krow-withus-worker-mobile/stage-v0.2.0 \ + -m "Staff Mobile v0.2.0 - Stage Release" + +# For PROD release +git tag -a krow-withus-worker-mobile/prod-v0.2.0 \ + -m "Staff Mobile v0.2.0 - Production Release" +``` + +**Push tags**: + +```bash +git push origin krow-withus-worker-mobile/dev-v0.2.0 +git push origin krow-withus-worker-mobile/stage-v0.2.0 +git push origin krow-withus-worker-mobile/prod-v0.2.0 +``` + +--- + +### Step 8: Create GitHub Release + +1. Go to: GitHub โ†’ Releases โ†’ Draft a new release +2. Fill in: + +``` +Tag version: krow-withus-worker-mobile/dev-v0.2.0 + +Release title: +Krow With Us - Worker Mobile - DEV - v0.2.0 + +Description: + +## ๐ŸŽฏ What's New in v0.2.0 + +### โœจ Features +- Shift details page with profile completion gating +- Benefits overview with sick leave tracking +- Auto-match shift recommendations + +### ๐Ÿ”ง Improvements +- Faster payment history loading +- Better shift booking UX +- Improved clock-in reliability + +### ๐Ÿ› Bug Fixes +- Fixed payment display date issue +- Fixed location verification on iOS 15+ +- Fixed crash when no shifts available + +## ๐Ÿ“ฆ Installation + +**iOS**: Download via TestFlight (internal) or App Store +**Android**: Download via Play Store + +## ๐Ÿ”— Dependencies + +Requires: +- Backend API v0.1.0+ +- DataConnect schema v0.3.0+ + +## โš ๏ธ Known Issues + +- Location permissions take 5-10 seconds on first install +- Workaround: Grant permissions in Settings app + +## ๐Ÿ“ Notes for QA + +- Test on actual device, not emulator +- Verify clock-in with GPS enabled +- Test all payment history edge cases + +--- + +Release Date: 2026-03-05 +Build Number: 6 +``` + +3. **Optional**: Attach build artifacts (APK/AAB from CodeMagic) +4. **Click**: "Publish release" + +--- + +## ๐Ÿ”„ Deployment Flow + +### Dev Release โ†’ Staging + +After dev is tested: + +```bash +# Create stage tag from same commit +git tag -a krow-withus-worker-mobile/stage-v0.2.0 \ + krow-withus-worker-mobile/dev-v0.2.0 \ + -m "Staff Mobile v0.2.0 - Stage Release" + +git push origin krow-withus-worker-mobile/stage-v0.2.0 + +# Deploy using CodeMagic or manual process +``` + +### Staging Release โ†’ Production + +After QA approval: + +```bash +# Create prod tag from same commit +git tag -a krow-withus-worker-mobile/prod-v0.2.0 \ + krow-withus-worker-mobile/stage-v0.2.0 \ + -m "Worker Mobile v0.2.0 - Production Release" + +git push origin krow-withus-worker-mobile/prod-v0.2.0 + +# Deploy to production +``` + +--- + +## ๐Ÿ“ฑ App Store Distribution + +### iOS App Store + +**Version Name**: Match pubspec.yaml version (0.2.0) +**Build Number**: Match pubspec.yaml build number (+6) + +**Steps**: +1. Ensure TestFlight build passed +2. Submit to App Review +3. Apple reviews (3-5 days) +4. Release to users (can be phased) + +### Google Play Store + +**Version Name**: Match pubspec.yaml version (0.2.0) +**Version Code**: Match pubspec.yaml build number (6) + +**Steps**: +1. Upload APK/AAB from CodeMagic +2. Fill in release notes (from CHANGELOG) +3. Submit for review +4. Google reviews (hours to 24h) +5. Release to users (can be phased, e.g., 10% then 100%) + +--- + +## ๐Ÿ”ง Pre-Release Checklist + +Before creating tags: + +- [ ] All PRs merged to main +- [ ] Code review complete +- [ ] Tests passing (unit, widget, integration) +- [ ] No lint/analysis errors: `flutter analyze` +- [ ] Pubspec.yaml version updated +- [ ] Build number incremented +- [ ] CHANGELOG.md updated with date +- [ ] Screenshots prepared (fresh) +- [ ] Release notes drafted +- [ ] No hardcoded strings (use translations) +- [ ] No debug prints remaining +- [ ] Performance acceptable (app launch < 3 seconds) +- [ ] Screen lock/unlock works +- [ ] Deep links tested +- [ ] Notifications working +- [ ] GPS/location working +- [ ] Camera permissions working +- [ ] All user-facing text reviewed + +--- + +## ๐ŸŽฏ Release Cadence + +### Development Releases (dev) + +- **Frequency**: Weekly +- **Day**: Monday 10:00 UTC +- **Process**: Quick, test in dev only + +### Staging Releases (stage) + +- **Frequency**: Bi-weekly (on sprint/feature completion) +- **Day**: Wednesday before production +- **Process**: Full QA testing, 1 week in staging + +### Production Releases (prod) + +- **Frequency**: Monthly (end of sprint) +- **Day**: Sunday/Monday morning (low traffic) +- **Process**: Full validation, market distribution + +--- + +## ๐Ÿ”— Related + +- [OVERALL_RELEASE_PLAN.md](./OVERALL_RELEASE_PLAN.md) - General strategy +- [HOTFIX_PROCESS.md](./HOTFIX_PROCESS.md) - Emergency procedures +- [../../CHANGELOG.md](../../CHANGELOG.md) - Root-level history + +--- + +## ๐Ÿ“ž Common Questions + +**Q: What if I need to release just one app (not both)?** +A: Completely fine! Each app is independent. Release when ready. + +**Q: Do I need to update the root CHANGELOG?** +A: Optional. If you do, keep it high-level and reference app-specific CHANGELOGs. + +**Q: What about shared packages inside mobile/?** +A: If shared package updated, mention in both app CHANGELOGs. + +**Q: How do I handle breaking changes?** +A: MAJOR version bump (0.x โ†’ 1.x) and clearly document in CHANGELOG. + +**Q: Can I release dev and stage on different days?** +A: Yes, no fixed schedule for dev/stage. Prod should be consistent (Sundays). + +--- + +**Last Updated**: 2026-03-05 +**Owner**: Mobile Engineering Team +**Status**: Active diff --git a/docs/RELEASE/OVERALL_RELEASE_PLAN.md b/docs/RELEASE/OVERALL_RELEASE_PLAN.md new file mode 100644 index 00000000..9ef4785f --- /dev/null +++ b/docs/RELEASE/OVERALL_RELEASE_PLAN.md @@ -0,0 +1,452 @@ +# KROW Workforce - Overall Release Plan + +**Document Version**: 1.0 +**Created**: 2026-03-05 +**Last Updated**: 2026-03-05 +**Product Scope**: All products (Mobile, Web, Backend, Database) + +--- + +## ๐Ÿ“‹ Overview + +This document outlines the release strategy for KROW Workforce monorepo containing 5 products: + +1. **Staff Mobile App** (Flutter - iOS/Android) +2. **Client Mobile App** (Flutter - iOS/Android) +3. **Web Dashboard** (React/Vite) +4. **Backend Services** (Node.js - Command API, Core API) +5. **Database** (Firebase Data Connect with PostgreSQL) + +--- + +## ๐Ÿ”— Versioning Strategy + +### Semantic Versioning (SemVer) + +All products use **Semantic Versioning 2.0.0**: + +``` +MAJOR.MINOR.PATCH-QUALIFIER +0.1.0 +1.2.3-rc.1 +``` + +- **MAJOR** (0โ†’1): Breaking changes, major features +- **MINOR** (1โ†’2): Backward-compatible new features +- **PATCH** (3โ†’4): Bug fixes, minor improvements +- **QUALIFIER** (optional): `-rc.1`, `-beta.1`, `-hotfix.1` + +### Version Independence + +Each product maintains **independent versioning**: +- Products release on their own schedule +- No requirement to synchronize versions +- Can release major updates independently + +--- + +## ๐Ÿท๏ธ Git Tag Naming Convention + +### Standard Format + +``` +/-v.. +``` + +### Products & Environments + +| Product | Tag Prefix | Environments | +|---------|-----------|---------------| +| Staff Mobile | `krow-withus-worker-mobile` | dev, stage, prod | +| Client Mobile | `krow-withus-client-mobile` | dev, stage, prod | +| Web Dashboard | `web-dashboard` | dev, stage, prod | +| Command API | `command-api` | dev, stage, prod | +| Core API | `core-api` | dev, stage, prod | +| DataConnect | `dataconnect` | stage, prod | + +### Environments + +- **dev**: Development releases (daily/weekly), unstable +- **stage**: Staging releases (bi-weekly), pre-production testing +- **prod**: Production releases (monthly), stable, customer-facing + +### Examples + +``` +krow-withus-worker-mobile/dev-v0.1.0 +krow-withus-client-mobile/stage-v0.2.0 +web-dashboard/prod-v1.0.0 +command-api/dev-v0.2.1 +core-api/prod-v0.1.0 +``` + +--- + +## ๐Ÿ“… Release Cadence + +### Development Releases (dev) + +- **Frequency**: Weekly or as-needed +- **Scope**: Feature completions, bug fixes +- **Duration**: Not guaranteed stable +- **Deployment**: Dev environment only +- **Who**: Development team + +### Staging Releases (stage) + +- **Frequency**: Bi-weekly (typically mid/end of sprint) +- **Scope**: Sprint completion, feature milestones +- **Duration**: 1-2 weeks stability expected +- **Deployment**: Staging environment for QA +- **Who**: QA team validates + +### Production Releases (prod) + +- **Frequency**: Monthly or sprint-based +- **Scope**: Feature milestone completion, critical fixes +- **Duration**: 4+ weeks standard support +- **Deployment**: Production environment (customer-facing) +- **Who**: Product owner approves, DevOps deploys + +--- + +## ๐Ÿ”„ Product Dependency & Deployment Order + +### Critical Path (for synchronized releases) + +Deploy in this order: + +1. **DataConnect Schema** (if schema changed) + - Deploy schema changes first + - All APIs depend on schema availability + +2. **Backend Services** (parallel OK) + - Command API + - Core API + - Both can deploy simultaneously + +3. **Web Dashboard** + - Can deploy once backend ready + - Test API endpoints stable + +4. **Mobile Apps** (parallel OK) + - Staff Mobile + - Client Mobile + - Both can deploy simultaneously, independent of web + +### Independent Releases + +Products **can release independently** if: +- No backend schema changes +- No breaking API changes +- No data migrations required + +Example: Staff Mobile can release UI improvements without web/backend changes. + +--- + +## ๐Ÿ“ CHANGELOG Management + +### Location & Structure + +Each major product maintains its own CHANGELOG: + +``` +apps/mobile/packages/features/staff/*/CHANGELOG.md +apps/mobile/packages/features/client/*/CHANGELOG.md +apps/web/CHANGELOG.md +backend/command-api/CHANGELOG.md +backend/core-api/CHANGELOG.md +CHANGELOG.md (root - high-level overview) +``` + +### Format + +```markdown +| Date | Version | Change | +|------|---------|--------| +| 2026-03-05 | 0.1.0 | Initial release - [feature list] | +``` + +### What to Track + +- Features added +- Bugs fixed +- Breaking changes (clearly marked โš ๏ธ) +- Dependencies upgraded +- Migration steps (if applicable) + +--- + +## โœ… Release Checklist + +### Pre-Release (48 hours before) + +- [ ] All PRs merged to main +- [ ] Code review complete +- [ ] All tests passing (unit, integration, E2E) +- [ ] No lint/type errors +- [ ] Mobile builds succeed (CodeMagic) +- [ ] Performance benchmarks acceptable +- [ ] Security scan completed +- [ ] CHANGELOG.md updated with all changes +- [ ] Documentation updated +- [ ] Team notified of pending release + +### Release Day + +- [ ] Update version numbers in all relevant files +- [ ] Update CHANGELOG with date +- [ ] Git commit: `git commit -m "chore: bump version to X.Y.Z"` +- [ ] Git push changes to main +- [ ] Create git tag: `git tag -a /-v -m "Release message"` +- [ ] Push tags: `git push origin ` +- [ ] Deploy to target environment +- [ ] Smoke tests pass +- [ ] Create GitHub Release page +- [ ] Notify stakeholders + +### Post-Release (24 hours) + +- [ ] Monitor error logs +- [ ] Verify all features work end-to-end +- [ ] Performance is acceptable +- [ ] No regressions reported +- [ ] Users updated if needed +- [ ] Document any issues + +--- + +## ๐Ÿ” Protected Tags + +### Branch Protection Rules + +**Production tags require approval:** + +- Tag pattern: `*/prod-v*` +- Require pull request review (1+ approval) +- Require status checks to pass +- Prevent force pushes +- Disable deletions + +**Staging tags recommended:** + +- Tag pattern: `*/stage-v*` +- Consider: Require at least 1 approval +- Status checks should pass + +**Dev tags open:** + +- Tag pattern: `*/dev-v*` +- No restrictions +- Allow fast iteration + +--- + +## ๐Ÿšจ Rollback Procedures + +### For Production Issues + +**If critical issue detected:** + +1. **Identify** the product and issue +2. **Assess** impact and severity +3. **Decide** rollback vs hotfix + - Rollback: Undo entire release + - Hotfix: Fix and re-release (see HOTFIX_PROCESS.md) +4. **Execute** rollback: + ```bash + # Revert commit + git revert -m 1 + git push origin main + + # Or switch traffic back to previous version + # (depends on deployment infrastructure) + ``` +5. **Communicate** with users +6. **Plan** hotfix or next release + +### Time Windows + +- **Awareness**: 15-30 minutes (monitoring) +- **Decision**: 15-30 minutes (severity assessment) +- **Execution**: 15-60 minutes (rollback deployment) +- **Verification**: 30-60 minutes (smoke tests) +- **Communication**: Immediate + 24h updates + +**Total**: 2-4 hours from detection to stable state + +--- + +## ๐Ÿ“Š Release Templates & Tools + +### Git Commands + +```bash +# Create tag +git tag -a krow-withus-worker-mobile/dev-v0.1.0 \ + -m "Staff Mobile v0.1.0 - Feature X" + +# Push tag +git push origin krow-withus-worker-mobile/dev-v0.1.0 + +# View tags for product +git tag -l "krow-withus-worker-mobile/*" --sort=-version:refname + +# See what's in a tag +git show krow-withus-worker-mobile/dev-v0.1.0 + +# Delete tag (if mistake) +git tag -d krow-withus-worker-mobile/dev-v0.1.0 +git push origin --delete krow-withus-worker-mobile/dev-v0.1.0 +``` + +### GitHub Release Template + +```markdown +# Krow With Us - Worker Mobile - DEV - v0.1.0 + +**Release Date**: [Date] +**Environment**: Development + +## What's New + +### โœจ Features +- Feature 1 description +- Feature 2 description + +### ๐Ÿ”ง Improvements +- Improvement 1 +- Improvement 2 + +### ๐Ÿ› Bug Fixes +- Bug fix 1 +- Bug fix 2 + +## Dependencies + +Requires: +- Backend API v0.1.0 or higher +- DataConnect schema v0.3.0 (if updated) + +## Installation + +[Download links & instructions] + +## Known Issues + +- Issue 1: [desc] (Workaround: ...) + +## Support + +contact: support@krow-workforce.com +``` + +--- + +## ๐Ÿ”„ Hotfix Releases + +See [HOTFIX_PROCESS.md](./HOTFIX_PROCESS.md) for emergency procedures. + +Quick summary: +1. Branch from production tag +2. Fix the issue +3. Bump PATCH version only +4. Test and deploy immediately +5. Create hotfix tag + +--- + +## ๐Ÿ“ฑ Mobile-Specific Release Process + +See [MOBILE_RELEASE_PLAN.md](./MOBILE_RELEASE_PLAN.md) for detailed mobile app process including: +- Staff Mobile vs Client Mobile differences +- Build number management +- CodeMagic integration +- App store distribution +- CHANGELOG per app + +--- + +## ๐ŸŽฏ Release Coordination + +### Single Product Release + +1. Update version files +2. Update CHANGELOG +3. Commit & push +4. Create tag +5. Deploy +6. Create GitHub Release + +**Time**: 30-45 minutes (excluding testing) + +### Multi-Product Release (e.g., v1.0.0) + +**Pre-release phase** (1 week before): +- Code freeze announced +- QA testing begins +- No new features merged + +**Release phase** (2-3 days): +- Staging release (all products) +- QA validation +- Product owner sign-off + +**Production phase** (1 day): +- Deploy in dependency order +- Smoke tests each product +- Monitor 24 hours +- User communication + +**Time**: 5-7 days total, 4 hours active deployment + +--- + +## ๐Ÿ“ž Roles & Responsibilities + +| Role | Responsibility | +|------|-----------------| +| **Developer** | Keep code release-ready, update versions | +| **QA** | Test staging releases, validate prod | +| **Release Engineer** | Create tags, manage deployment, monitor | +| **Product Owner** | Approve releases, communicate timeline | +| **DevOps** | Infrastructure ready, deployment scripts | + +--- + +## ๐Ÿ“Š Success Metrics + +Track these per release: + +- **Lead Time**: Time from code commit to production +- **Deployment Frequency**: How often you release +- **Change Failure Rate**: % of releases needing rollback +- **Time to Recovery**: Time to fix production issues +- **User Adoption**: % of users on latest version + +--- + +## ๐Ÿ“š Related Documentation + +- [MOBILE_RELEASE_PLAN.md](./MOBILE_RELEASE_PLAN.md) - Mobile app releases +- [HOTFIX_PROCESS.md](./HOTFIX_PROCESS.md) - Emergency procedures +- [../../RELEASE_STRATEGY.md](../../RELEASE_STRATEGY.md) - Original detailed guide +- [../../CHANGELOG.md](../../CHANGELOG.md) - Root version history + +--- + +## โœ… Implementation Status + +- โœ… Versioning strategy: SemVer +- โœ… Environments: dev, stage, prod +- โœ… Tag naming: Product-specific with brand prefix +- โœ… Product dependencies: Defined +- โœ… Release cadence: 3 levels +- โณ GitHub Actions: To be set up +- โณ Deployment automation: To be set up + +--- + +**Next Step**: Review [MOBILE_RELEASE_PLAN.md](./MOBILE_RELEASE_PLAN.md) for app-specific process. + diff --git a/makefiles/tools.mk b/makefiles/tools.mk index 111433e2..823a491e 100644 --- a/makefiles/tools.mk +++ b/makefiles/tools.mk @@ -1,6 +1,6 @@ # --- Development Tools --- -.PHONY: install-git-hooks sync-prototypes install-melos clean-branches +.PHONY: install-git-hooks sync-prototypes install-melos clean-branches setup-mobile-ci-secrets install-melos: @if ! command -v melos >/dev/null 2>&1; then \ @@ -54,3 +54,8 @@ clean-branches: fi; \ done; \ echo "\nโœ… Done! Deleted $$DELETED branch(es), skipped $$SKIPPED protected branch(es)." + +setup-mobile-ci-secrets: + @echo "--> Running GitHub Secrets setup helper for APK signing..." + @./.github/scripts/setup-mobile-github-secrets.sh + @echo "\n๐Ÿ“š For more information, see: docs/RELEASE/APK_SIGNING_SETUP.md"