Compare commits

...

2 Commits

Author SHA1 Message Date
489c0271c9 refactor: rename package scope from @caldav to @calchat
Rename all workspace packages to reflect the actual project name:
- @caldav/client -> @calchat/client
- @caldav/server -> @calchat/server
- @caldav/shared -> @calchat/shared
- Root package: caldav-mono -> calchat-mono

Update all import statements across client and server to use the new
package names. Update default MongoDB database name and logging service
identifier accordingly.
2026-01-12 19:46:53 +01:00
fef30d428d feat: add EAS build configuration for local APK builds
- Add eas.json with development, preview, and production profiles
- Configure preview profile for APK builds (arm64-v8a only)
- Add build:apk npm script for local builds
- Update app.json with app name and Android package
- Add expo-build-properties dependency
- Update CLAUDE.md with build documentation
2026-01-12 19:29:52 +01:00
40 changed files with 180 additions and 3327 deletions

View File

@@ -18,18 +18,19 @@ npm run format # Format all TypeScript files with Prettier
### Client (apps/client) - Expo React Native app
```bash
npm run start -w @caldav/client # Start Expo dev server
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 start -w @calchat/client # Start Expo dev server
npm run android -w @calchat/client # Start on Android
npm run ios -w @calchat/client # Start on iOS
npm run web -w @calchat/client # Start web version
npm run lint -w @calchat/client # Run ESLint
npm run build:apk -w @calchat/client # Build APK locally with EAS
```
### Server (apps/server) - Express.js backend
```bash
npm run dev -w @caldav/server # Start dev server with hot reload (tsx watch)
npm run build -w @caldav/server # Compile TypeScript
npm run start -w @caldav/server # Run compiled server (port 3000)
npm run dev -w @calchat/server # Start dev server with hot reload (tsx watch)
npm run build -w @calchat/server # Compile TypeScript
npm run start -w @calchat/server # Run compiled server (port 3000)
```
## Technology Stack
@@ -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 |
@@ -55,9 +57,9 @@ npm run start -w @caldav/server # Run compiled server (port 3000)
### Workspace Structure
```
apps/client - @caldav/client - Expo React Native app
apps/server - @caldav/server - Express.js backend
packages/shared - @caldav/shared - Shared TypeScript types and models
apps/client - @calchat/client - Expo React Native app
apps/server - @calchat/server - Express.js backend
packages/shared - @calchat/shared - Shared TypeScript types and models
```
### Frontend Architecture (apps/client)
@@ -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 @calchat/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/`:

View File

@@ -1,50 +1,37 @@
{
"expo": {
"jsEngine": "hermes",
"name": "caldav",
"slug": "caldav",
"name": "CalChat",
"slug": "calchat",
"version": "1.0.0",
"orientation": "portrait",
"icon": "./assets/images/icon.png",
"scheme": "caldav",
"scheme": "calchat",
"userInterfaceStyle": "automatic",
"newArchEnabled": true,
"ios": {
"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"
}
}
}
}

28
apps/client/eas.json Normal file
View File

@@ -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": {}
}
}

View File

@@ -1,5 +1,5 @@
{
"name": "@caldav/client",
"name": "@calchat/client",
"main": "expo-router/entry",
"version": "1.0.0",
"scripts": {
@@ -8,16 +8,18 @@
"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": "*",
"@calchat/shared": "*",
"@expo/vector-icons": "^15.0.3",
"@react-navigation/bottom-tabs": "^7.4.0",
"@react-navigation/elements": "^2.6.3",
"@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",

View File

@@ -7,7 +7,7 @@ import {
ScrollView,
Alert,
} from "react-native";
import { DAYS, MONTHS, Month, ExpandedEvent } from "@caldav/shared";
import { DAYS, MONTHS, Month, ExpandedEvent } from "@calchat/shared";
import Header from "../../components/Header";
import { EventCard } from "../../components/EventCard";
import React, {

View File

@@ -18,7 +18,7 @@ import {
chatMessageToMessageData,
MessageData,
} from "../../stores";
import { ProposedEventChange } from "@caldav/shared";
import { ProposedEventChange } from "@calchat/shared";
import { ProposedEventCard } from "../../components/ProposedEventCard";
import { Ionicons } from "@expo/vector-icons";

View File

@@ -1,5 +1,5 @@
import { View, Pressable } from "react-native";
import { ExpandedEvent } from "@caldav/shared";
import { ExpandedEvent } from "@calchat/shared";
import { Feather } from "@expo/vector-icons";
import currentTheme from "../Themes";
import { EventCardBase } from "./EventCardBase";

View File

@@ -1,5 +1,5 @@
import { View, Text, Modal, Pressable } from "react-native";
import { CreateEventDTO } from "@caldav/shared";
import { CreateEventDTO } from "@calchat/shared";
type EventConfirmDialogProps = {
visible: boolean;

View File

@@ -1,5 +1,5 @@
import { View, Text, Pressable } from "react-native";
import { ProposedEventChange } from "@caldav/shared";
import { ProposedEventChange } from "@calchat/shared";
import currentTheme from "../Themes";
import { EventCardBase } from "./EventCardBase";

View File

@@ -1,4 +1,4 @@
import { LoginDTO, CreateUserDTO, AuthResponse } from "@caldav/shared";
import { LoginDTO, CreateUserDTO, AuthResponse } from "@calchat/shared";
import { ApiClient } from "./ApiClient";
import { useAuthStore } from "../stores";

View File

@@ -7,7 +7,7 @@ import {
CreateEventDTO,
UpdateEventDTO,
EventAction,
} from "@caldav/shared";
} from "@calchat/shared";
import { ApiClient } from "./ApiClient";
interface ConfirmEventRequest {

View File

@@ -3,7 +3,7 @@ import {
CreateEventDTO,
UpdateEventDTO,
ExpandedEvent,
} from "@caldav/shared";
} from "@calchat/shared";
import { ApiClient } from "./ApiClient";
export const EventService = {

View File

@@ -1,6 +1,6 @@
import { create } from "zustand";
import { Platform } from "react-native";
import { User } from "@caldav/shared";
import { User } from "@calchat/shared";
import * as SecureStore from "expo-secure-store";
const USER_STORAGE_KEY = "auth_user";

View File

@@ -1,5 +1,5 @@
import { create } from "zustand";
import { ChatMessage, ProposedEventChange } from "@caldav/shared";
import { ChatMessage, ProposedEventChange } from "@calchat/shared";
type BubbleSide = "left" | "right";

View File

@@ -1,5 +1,5 @@
import { create } from "zustand";
import { ExpandedEvent } from "@caldav/shared";
import { ExpandedEvent } from "@calchat/shared";
interface EventsState {
events: ExpandedEvent[];

View File

@@ -1,5 +1,5 @@
{
"name": "@caldav/server",
"name": "@calchat/server",
"version": "1.0.0",
"private": true,
"scripts": {
@@ -8,7 +8,7 @@
"start": "node dist/app.js"
},
"dependencies": {
"@caldav/shared": "*",
"@calchat/shared": "*",
"bcrypt": "^6.0.0",
"dotenv": "^16.4.7",
"express": "^5.2.1",

View File

@@ -1,5 +1,5 @@
import OpenAI from "openai";
import { ProposedEventChange } from "@caldav/shared";
import { ProposedEventChange } from "@calchat/shared";
import { AIProvider, AIContext, AIResponse } from "../services/interfaces";
import {
buildSystemPrompt,

View File

@@ -1,4 +1,4 @@
import { CalendarEvent } from "@caldav/shared";
import { CalendarEvent } from "@calchat/shared";
// German date/time formatting helpers
export const formatDate = (d: Date) => d.toLocaleDateString("de-DE");

View File

@@ -3,7 +3,7 @@ import {
getDay,
Day,
DAY_TO_GERMAN,
} from "@caldav/shared";
} from "@calchat/shared";
import { AIContext } from "../../services/interfaces";
import { formatDate, formatTime, formatDateTime } from "./eventFormatter";

View File

@@ -20,7 +20,7 @@ import { logger } from "./logging";
const app = express();
const port = process.env.PORT || 3000;
const mongoUri = process.env.MONGODB_URI || "mongodb://localhost:27017/caldav";
const mongoUri = process.env.MONGODB_URI || "mongodb://localhost:27017/calchat";
// Middleware
app.use(express.json());

View File

@@ -5,7 +5,7 @@ import {
UpdateEventDTO,
EventAction,
GetMessagesOptions,
} from "@caldav/shared";
} from "@calchat/shared";
import { ChatService } from "../services";
import { createLogger } from "../logging";
import { AuthenticatedRequest } from "./AuthMiddleware";

View File

@@ -32,7 +32,7 @@ export const logger = pino({
}
: undefined,
base: {
service: "caldav-server",
service: "calchat-server",
},
});

View File

@@ -4,7 +4,7 @@ import {
CreateMessageDTO,
GetMessagesOptions,
UpdateMessageDTO,
} from "@caldav/shared";
} from "@calchat/shared";
import { ChatRepository } from "../../services/interfaces";
import { Logged } from "../../logging";
import { ChatMessageModel, ConversationModel } from "./models";

View File

@@ -1,4 +1,4 @@
import { CalendarEvent, CreateEventDTO, UpdateEventDTO } from "@caldav/shared";
import { CalendarEvent, CreateEventDTO, UpdateEventDTO } from "@calchat/shared";
import { EventRepository } from "../../services/interfaces";
import { Logged } from "../../logging";
import { EventModel } from "./models";

View File

@@ -1,4 +1,4 @@
import { User } from "@caldav/shared";
import { User } from "@calchat/shared";
import { UserRepository, CreateUserData } from "../../services/interfaces";
import { Logged } from "../../logging";
import { UserModel, UserDocument } from "./models";

View File

@@ -5,7 +5,7 @@ import {
CreateEventDTO,
UpdateEventDTO,
ProposedEventChange,
} from "@caldav/shared";
} from "@calchat/shared";
import { IdVirtual } from "./types";
export interface ChatMessageDocument extends Omit<ChatMessage, "id">, Document {

View File

@@ -1,5 +1,5 @@
import mongoose, { Schema, Document, Model } from "mongoose";
import { CalendarEvent } from "@caldav/shared";
import { CalendarEvent } from "@calchat/shared";
import { IdVirtual } from "./types";
export interface EventDocument extends Omit<CalendarEvent, "id">, Document {

View File

@@ -1,5 +1,5 @@
import mongoose, { Schema, Document, Model } from "mongoose";
import { User } from "@caldav/shared";
import { User } from "@calchat/shared";
import { IdVirtual } from "./types";
export interface UserDocument extends Omit<User, "id">, Document {

View File

@@ -1,4 +1,4 @@
import { User, CreateUserDTO, LoginDTO, AuthResponse } from "@caldav/shared";
import { User, CreateUserDTO, LoginDTO, AuthResponse } from "@calchat/shared";
import { UserRepository } from "./interfaces";
import * as jwt from "../utils/jwt";
import * as password from "../utils/password";

View File

@@ -10,7 +10,7 @@ import {
UpdateEventDTO,
EventAction,
CreateMessageDTO,
} from "@caldav/shared";
} from "@calchat/shared";
import { ChatRepository, EventRepository, AIProvider } from "./interfaces";
import { getWeeksOverview, getMonthOverview } from "../utils/eventFormatters";

View File

@@ -3,7 +3,7 @@ import {
CreateEventDTO,
UpdateEventDTO,
ExpandedEvent,
} from "@caldav/shared";
} from "@calchat/shared";
import { EventRepository } from "./interfaces";
import { expandRecurringEvents } from "../utils/recurrenceExpander";

View File

@@ -2,7 +2,7 @@ import {
CalendarEvent,
ChatMessage,
ProposedEventChange,
} from "@caldav/shared";
} from "@calchat/shared";
export interface AIContext {
userId: string;

View File

@@ -4,7 +4,7 @@ import {
CreateMessageDTO,
GetMessagesOptions,
UpdateMessageDTO,
} from "@caldav/shared";
} from "@calchat/shared";
export interface ChatRepository {
// Conversations

View File

@@ -1,4 +1,4 @@
import { CalendarEvent, CreateEventDTO, UpdateEventDTO } from "@caldav/shared";
import { CalendarEvent, CreateEventDTO, UpdateEventDTO } from "@calchat/shared";
export interface EventRepository {
findById(id: string): Promise<CalendarEvent | null>;

View File

@@ -1,4 +1,4 @@
import { User } from "@caldav/shared";
import { User } from "@calchat/shared";
export interface CreateUserData {
email: string;

View File

@@ -5,7 +5,7 @@ import {
DAY_TO_GERMAN_SHORT,
MONTH_TO_GERMAN,
ExpandedEvent,
} from "@caldav/shared";
} from "@calchat/shared";
import { EventRepository } from "../services/interfaces";
import { expandRecurringEvents } from "./recurrenceExpander";

View File

@@ -1,5 +1,5 @@
import { RRule, rrulestr } from "rrule";
import { CalendarEvent, ExpandedEvent } from "@caldav/shared";
import { CalendarEvent, ExpandedEvent } from "@calchat/shared";
// Convert local time to "fake UTC" for rrule
// rrule interprets all dates as UTC internally, so we need to trick it

3317
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
{
"name": "caldav-mono",
"name": "calchat-mono",
"version": "1.0.0",
"private": true,
"workspaces": [

View File

@@ -1,5 +1,5 @@
{
"name": "@caldav/shared",
"name": "@calchat/shared",
"version": "1.0.0",
"private": true,
"main": "./src/index.ts",