Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
187 changes: 187 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

**SUMilanApp** is a web application for the SingularityU Milan Chapter that enhances event attendance experiences. It provides event information, live streaming, NFT certificate minting, and multilingual support (English/Italian).

**Live version**: https://app.singularityumilan.com

## Architecture

### Monorepo Structure (Nx Workspace)
- **`apps/sumilan-app/`**: Main Ionic React application
- **`apps/sumilan-app-e2e/`**: Cypress end-to-end tests
- **`apps/smart-contract-api/`**: Smart contract API backend
- **`apps/notify-activist-request/`**: Notification service
- **`libs/api/`**: GraphQL API client library
- **`libs/smart-contract/`**: Solidity smart contracts with Hardhat
- **`libs/eventbrite-wrapper/`**: Eventbrite API integration

### Technology Stack
- **Frontend**: Ionic + React + TypeScript
- **Backend**: Supabase (database + authentication)
- **Blockchain**: Ethereum smart contracts (Hardhat + Solidity 0.8.9)
- **Mobile**: Capacitor for iOS/Android deployment
- **Monorepo**: Nx workspace management
- **Testing**: Jest + Cypress + Hardhat tests

### Key Features
- Event management with live streaming
- NFT certificate minting for attendance
- Multi-language support (i18n)
- Progressive Web App capabilities
- Eventbrite integration for ticket validation
- Blockchain-based certificate verification

## Development Commands

### Core Development
```bash
# Install dependencies
npm install

# Start development server (with SSL and HMR)
npx nx run sumilan-app:serve

# Build for production
npx nx run sumilan-app:build:production

# Run tests
npx nx run sumilan-app:test

# Run linting
npx nx run sumilan-app:lint

# Run all tests in workspace
npm test
```

### Mobile Development (Capacitor)
```bash
# Add mobile platforms
npx nx run sumilan-app:add:ios
npx nx run sumilan-app:add:android

# Sync web assets to mobile
npx nx run sumilan-app:sync:ios
npx nx run sumilan-app:sync:android

# Open in native IDE
npx nx run sumilan-app:open:ios
npx nx run sumilan-app:open:android
```

### Smart Contract Development
```bash
# Navigate to smart contract directory
cd libs/smart-contract

# Compile contracts
npx hardhat compile

# Run contract tests
npx hardhat test

# Deploy to test network (Ropsten)
npx hardhat run scripts/deploy.js --network ropsten
```

## Environment Setup

Required environment variables in `.env`:
```
NX_SUPABASE_URL="your_supabase_url"
NX_SUPABASE_GRAPHQL_ENDPOINT="your_supabase_url/graphql/v1"
NX_SUPABASE_PUBLIC_KEY="your_supabase_public_key"
NX_IBM_EVENTBRITE_WRAPPER_KEY="your_ibm_cloud_function_key"
NX_AWS_LAMBDA_CERTIFICATE_API_KEY="your_aws_lambda_api_key"
ALCHEMY_API_URL="your_alchemy_api_url"
METAMASK_PRIVATE_KEY="your_metamask_private_key"
```

## Code Architecture

### Path Mappings (tsconfig.base.json)
- `@sumilan-app/api` → `libs/api/src/index.ts`
- `@sumilan-app/eventbrite-wrapper` → `libs/eventbrite-wrapper/src/index.js`
- `@sumilan-app/smart-contract` → `libs/smart-contract/src/index.js`

### Main App Structure
- **`/app/components/`**: Reusable React components
- **`/app/pages/`**: Page-level components with routing
- **`/app/services/`**: API integrations and business logic
- **`/app/store/`**: Redux Toolkit state management
- **`/app/contexts/`**: React contexts for global state
- **`/app/utils/`**: Utility functions and helpers
- **`/assets/i18n/`**: Internationalization files (en.json, it.json)

### Key Services
- **`supabase.ts`**: Database and authentication client
- **`web3.ts`**: Web3 blockchain integration
- **`eventbriteWrapper.ts`**: Eventbrite API integration
- **`mintApi.ts`**: NFT certificate minting service
- **`SUMilanCertificate.ts`**: Smart contract interaction

### State Management
- **Redux Toolkit** for global state
- **React Context** for authentication and video player state
- **React Hook Form** for form management

## Testing

### Unit Tests (Jest)
```bash
# Run specific app tests
npx nx run sumilan-app:test

# Run specific lib tests
npx nx run api:test
npx nx run smart-contract:test
```

### E2E Tests (Cypress)
```bash
# Run e2e tests
npx nx run sumilan-app-e2e:e2e
```

### Smart Contract Tests (Hardhat)
```bash
cd libs/smart-contract
npx hardhat test
```

## Deployment

### Web Deployment
Build output is generated in `dist/apps/sumilan-app/` ready for static hosting.

### Mobile Deployment
1. Build web assets: `npx nx run sumilan-app:build:production`
2. Sync to mobile: `npx nx run sumilan-app:sync:ios` or `npx nx run sumilan-app:sync:android`
3. Open in Xcode/Android Studio for final build and deployment

## Important Notes

### Development Server
- Uses SSL by default (`ssl: true` in serve options)
- Hot Module Replacement (HMR) enabled for fast development
- Serves on HTTPS for testing PWA features and Web3 integration

### Blockchain Integration
- Smart contracts deployed on Ropsten testnet
- Uses Hardhat for development and testing
- OpenZeppelin contracts for security
- Upgradeable contract pattern implemented

### Internationalization
- Files: `assets/i18n/en.json` and `assets/i18n/it.json`
- Uses `react-i18next` for translation management
- Automatic language detection based on browser settings

### Performance
- Nx caching enabled for build, lint, test, and e2e operations
- PWA with service worker for offline capabilities
- Optimized production builds with code splitting
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import './EventTimeComponent.css';
const dateFormat = Object.assign({}, DateTime.DATETIME_MED);

interface EventTimeProps {
date: string;
date: string | null | undefined;
duration: number; // in minutes
}

Expand All @@ -33,7 +33,7 @@ const TimeContainer: React.FC = ({ children }) => {
};

const EventTimeComponent: React.FC<EventTimeProps> = ({ date, duration }) => {
const dt = DateTime.fromISO(date);
const dt = date ? DateTime.fromISO(date) : DateTime.now();
const { timeStatus: eventTimeStatus } = useContext(EventTimeContext) as EventTimeContextModel;

const { t } = useTranslation();
Expand Down
4 changes: 2 additions & 2 deletions apps/sumilan-app/src/app/contexts/EventTime.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ import { Event_Time_Status } from "@sumilan-app/api";
export const EventTimeContext = createContext<EventTimeContextModel | null>(null);

type Props = {
date: string;
date: string | null | undefined;
duration: number;
};

export const EventTimeProvider: React.FC<Props> = ({ children, date, duration }) => {
const dt = DateTime.fromISO(date);
const dt = date ? DateTime.fromISO(date) : DateTime.now();
const [timeStatus, setTimeStatus] = useState(getEventTimeStatus(dt, duration));

useEffect(() => {
Expand Down
2 changes: 1 addition & 1 deletion apps/sumilan-app/src/app/models/activist-request.model.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export interface ActivistRequest {
id: number;
id: string;
email: string;
accepted: boolean;
created_at: string;
Expand Down
20 changes: 7 additions & 13 deletions apps/sumilan-app/src/app/pages/Home/Home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,13 @@ import { Events, Event_Time_Status, useGetEventsQuery } from '@sumilan-app/api';
import './Home.css';

interface GroupedEventsModel {
passed: Partial<Events>[];
scheduled: Partial<Events>[];
today: Partial<Events>[];
passed: Events[];
scheduled: Events[];
today: Events[];
}

interface EventsListComponentWithRouteProps extends RouteComponentProps {
events: Partial<Events>[];
events: Events[];
title: string;
}

Expand Down Expand Up @@ -128,17 +128,11 @@ const Home: React.FC<RouteComponentProps> = (props: RouteComponentProps) => {
ev?.event_description?.toLowerCase().includes(searchQuery)
)) {
if (ev?.event_time_status === Event_Time_Status.Passed) {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
//@ts-ignore
groupedEvents.passed.push(ev);
groupedEvents.passed.push(ev as Events);
} else if (ev?.event_time_status === Event_Time_Status.Scheduled) {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
//@ts-ignore
groupedEvents.scheduled.push(ev);
groupedEvents.scheduled.push(ev as Events);
} else {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
//@ts-ignore
groupedEvents.today.push(ev);
groupedEvents.today.push(ev as Events);
}
}
}
Expand Down
9 changes: 9 additions & 0 deletions graphql.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,15 @@
"typescript-urql"
],
"config": {
"scalars": {
"BigInt": "string",
"Cursor": "string",
"Date": "string",
"Datetime": "string",
"JSON": "Record<string, any>",
"Time": "string",
"UUID": "string"
},
"skipTypeNameForRoot": true,
"skipTypename": true,
"withHooks": true,
Expand Down
14 changes: 7 additions & 7 deletions libs/api/src/lib/generated/generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ export type Scalars = {
Boolean: boolean;
Int: number;
Float: number;
BigInt: any;
Cursor: any;
Date: any;
Datetime: any;
JSON: any;
Time: any;
UUID: any;
BigInt: string;
Cursor: string;
Date: string;
Datetime: string;
JSON: Record<string, any>;
Time: string;
UUID: string;
};

/** Boolean expression comparing fields on type "BigInt" */
Expand Down
22 changes: 13 additions & 9 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
"@reduxjs/toolkit": "^1.8.0",
"@supabase/supabase-js": "^1.32.1",
"animate.css": "^4.1.1",
"caniuse-lite": "^1.0.30001726",
"core-js": "^3.6.5",
"date-fns": "^2.28.0",
"dotenv": "^16.0.0",
Expand Down