diff --git a/CLAUDE.md b/CLAUDE.md index 0050530..5abc33c 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -23,6 +23,7 @@ npm run android -w @caldav/client # Start on Android npm run ios -w @caldav/client # Start on iOS npm run web -w @caldav/client # Start web version npm run lint -w @caldav/client # Run ESLint +npm run build:apk -w @caldav/client # Build APK locally with EAS ``` ### Server (apps/server) - Express.js backend @@ -42,6 +43,7 @@ npm run start -w @caldav/server # Run compiled server (port 3000) | | NativeWind | Tailwind CSS for React Native | | | Zustand | State management | | | FlashList | High-performance lists | +| | EAS Build | Local APK/IPA builds | | Backend | Express.js | Web framework | | | MongoDB | Database | | | Mongoose | ODM | @@ -404,6 +406,29 @@ NODE_ENV=development # development = pretty logs, production = JSON - `ChatStore`: Zustand store with addMessage(), addMessages(), updateMessage(), clearMessages() - loads from server on mount and persists across tab switches - Event Detail and Note screens exist as skeletons +## Building + +### Local APK Build with EAS +```bash +npm run build:apk -w @caldav/client +``` + +This uses the `preview` profile from `eas.json` which builds an APK with: +- `arm64-v8a` architecture only (smaller APK size) +- No credentials required (`withoutCredentials: true`) +- Internal distribution + +**Requirements:** Android SDK and Java must be installed locally. + +**EAS Configuration:** `apps/client/eas.json` contains build profiles: +- `development`: Development client with internal distribution +- `preview`: APK build for testing (used by `build:apk`) +- `production`: Production build with auto-increment versioning + +**App Identity:** +- Package name: `com.gilmour109.calchat` +- EAS Project ID: `b722dde6-7d89-48ff-9095-e007e7c7da87` + ## Documentation Detailed architecture diagrams are in `docs/`: diff --git a/apps/client/app.json b/apps/client/app.json index 4f2a3df..9d6c2ad 100644 --- a/apps/client/app.json +++ b/apps/client/app.json @@ -1,11 +1,10 @@ { "expo": { "jsEngine": "hermes", - "name": "caldav", + "name": "CalChat", "slug": "caldav", "version": "1.0.0", "orientation": "portrait", - "icon": "./assets/images/icon.png", "scheme": "caldav", "userInterfaceStyle": "automatic", "newArchEnabled": true, @@ -13,38 +12,26 @@ "supportsTablet": true }, "android": { - "adaptiveIcon": { - "backgroundColor": "#E6F4FE", - "foregroundImage": "./assets/images/android-icon-foreground.png", - "backgroundImage": "./assets/images/android-icon-background.png", - "monochromeImage": "./assets/images/android-icon-monochrome.png" - }, + "package": "com.gilmour109.calchat", "edgeToEdgeEnabled": true, "predictiveBackGestureEnabled": false }, "web": { "output": "static", - "favicon": "./assets/images/favicon.png", "bundler": "metro" }, "plugins": [ - "expo-router", - [ - "expo-splash-screen", - { - "image": "./assets/images/splash-icon.png", - "imageWidth": 200, - "resizeMode": "contain", - "backgroundColor": "#ffffff", - "dark": { - "backgroundColor": "#000000" - } - } - ] + "expo-router" ], "experiments": { "typedRoutes": true, "reactCompiler": true + }, + "extra": { + "router": {}, + "eas": { + "projectId": "b722dde6-7d89-48ff-9095-e007e7c7da87" + } } } } diff --git a/apps/client/eas.json b/apps/client/eas.json new file mode 100644 index 0000000..d87b9d4 --- /dev/null +++ b/apps/client/eas.json @@ -0,0 +1,28 @@ +{ + "cli": { + "version": ">= 16.28.0", + "appVersionSource": "remote" + }, + "build": { + "development": { + "developmentClient": true, + "distribution": "internal" + }, + "preview": { + "distribution": "internal", + "android": { + "buildType": "apk", + "withoutCredentials": true + }, + "env": { + "ORG_GRADLE_PROJECT_reactNativeArchitectures": "arm64-v8a" + } + }, + "production": { + "autoIncrement": true + } + }, + "submit": { + "production": {} + } +} diff --git a/apps/client/package.json b/apps/client/package.json index ed1416c..443c098 100644 --- a/apps/client/package.json +++ b/apps/client/package.json @@ -8,7 +8,8 @@ "android": "expo start --android", "ios": "expo start --ios", "web": "expo start --web", - "lint": "expo lint" + "lint": "expo lint", + "build:apk": "eas build --platform android --profile preview --local" }, "dependencies": { "@caldav/shared": "*", @@ -18,6 +19,7 @@ "@react-navigation/native": "^7.1.8", "@shopify/flash-list": "^2.0.2", "expo": "~54.0.25", + "expo-build-properties": "^1.0.10", "expo-constants": "~18.0.10", "expo-font": "~14.0.9", "expo-haptics": "~15.0.7", diff --git a/package-lock.json b/package-lock.json index b1cde84..6440463 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,6 +28,7 @@ "@react-navigation/native": "^7.1.8", "@shopify/flash-list": "^2.0.2", "expo": "~54.0.25", + "expo-build-properties": "^1.0.10", "expo-constants": "~18.0.10", "expo-font": "~14.0.9", "expo-haptics": "~15.0.7", @@ -7303,6 +7304,53 @@ "react-native": "*" } }, + "node_modules/expo-build-properties": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/expo-build-properties/-/expo-build-properties-1.0.10.tgz", + "integrity": "sha512-mFCZbrbrv0AP5RB151tAoRzwRJelqM7bCJzCkxpu+owOyH+p/rFC/q7H5q8B9EpVWj8etaIuszR+gKwohpmu1Q==", + "license": "MIT", + "dependencies": { + "ajv": "^8.11.0", + "semver": "^7.6.0" + }, + "peerDependencies": { + "expo": "*" + } + }, + "node_modules/expo-build-properties/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/expo-build-properties/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" + }, + "node_modules/expo-build-properties/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/expo-constants": { "version": "18.0.11", "resolved": "https://registry.npmjs.org/expo-constants/-/expo-constants-18.0.11.tgz", @@ -8013,6 +8061,22 @@ "dev": true, "license": "MIT" }, + "node_modules/fast-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", + "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, "node_modules/fastq": { "version": "1.19.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz",