Initial commit: Family Planner application

Complete family planning application with:
- React frontend with TypeScript
- Node.js/Express backend with TypeScript
- Python ingestion service for document processing
- Planning ingestion service with LLM integration
- Shared UI components and type definitions
- OAuth integration for calendar synchronization
- Comprehensive documentation

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
philippe
2025-10-14 10:43:33 +02:00
commit fdd72c1135
239 changed files with 44160 additions and 0 deletions

View File

@@ -0,0 +1,13 @@
module.exports = {
root: true,
parser: "@typescript-eslint/parser",
parserOptions: {
ecmaVersion: 2020,
sourceType: "module"
},
env: {
es2021: true
},
plugins: ["@typescript-eslint"],
extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended", "prettier"]
};

6
shared/types/.prettierrc Normal file
View File

@@ -0,0 +1,6 @@
{
"singleQuote": true,
"trailingComma": "all",
"tabWidth": 2,
"printWidth": 90
}

22
shared/types/package.json Normal file
View File

@@ -0,0 +1,22 @@
{
"name": "@family-planner/types",
"version": "0.1.0",
"private": true,
"type": "module",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"build": "tsc -p tsconfig.json",
"lint": "eslint \"src/**/*.ts\" --max-warnings=0",
"format": "prettier --write \"src/**/*.ts\""
},
"devDependencies": {
"typescript": "^5.6.0",
"@types/node": "^20.11.0",
"eslint": "^9.0.0",
"@typescript-eslint/parser": "^7.0.0",
"@typescript-eslint/eslint-plugin": "^7.0.0",
"eslint-config-prettier": "^9.0.0",
"prettier": "^3.3.0"
}
}

View File

@@ -0,0 +1 @@
export {};

92
shared/types/src/index.ts Normal file
View File

@@ -0,0 +1,92 @@
export type ChildAvatar =
| { kind: "preset"; url: string; name: string }
| { kind: "custom"; url: string; name?: string };
export type SchoolRegion =
| "zone-a"
| "zone-b"
| "zone-c"
| "corse"
| "guadeloupe"
| "guyane"
| "martinique"
| "reunion"
| "mayotte";
export type ChildProfile = {
id: string;
fullName: string;
colorHex: string;
email?: string;
birthDate?: string;
notes?: string;
avatar?: ChildAvatar;
schoolRegion?: SchoolRegion;
createdAt?: string;
deletedAt?: string;
};
export type ActivityCategory = "school" | "sport" | "medical" | "event" | "other";
export type ActivityReminder = {
id: string;
offsetMinutes: number;
channel: "push" | "email" | "sms" | "device";
};
export type ActivityItem = {
id: string;
title: string;
category: ActivityCategory;
description?: string;
location?: string;
startDateTime: string;
endDateTime: string;
reminders: ActivityReminder[];
metadata?: Record<string, string>;
};
export type ScheduleItem = {
id: string;
childId: string;
periodStart: string;
periodEnd: string;
sourceFileUrl?: string;
activities: ActivityItem[];
status: "processing" | "ready" | "failed";
};
export type AlertItem = {
id: string;
childId: string;
scheduleId: string;
activityId: string;
title: string;
triggerDateTime: string;
channel: "push" | "email" | "sms" | "device";
status: "pending" | "sent" | "dismissed";
};
export type HolidayType = "school" | "public" | "custom";
export type Holiday = {
id: string;
title: string;
startDate: string;
endDate: string;
type: HolidayType;
description?: string;
zones?: SchoolRegion[];
};
export type PersonalLeave = {
id: string;
profileId: string;
title: string;
startDate: string;
endDate: string;
isAllDay: boolean;
notes?: string;
source?: "manual" | "calendar";
createdAt?: string;
};

View File

@@ -0,0 +1,15 @@
{
"compilerOptions": {
"declaration": true,
"declarationMap": true,
"emitDeclarationOnly": false,
"module": "ESNext",
"target": "ES2020",
"moduleResolution": "Node",
"outDir": "dist",
"rootDir": "src",
"strict": true,
"esModuleInterop": true
},
"include": ["src"]
}

25
shared/ui/.eslintrc.cjs Normal file
View File

@@ -0,0 +1,25 @@
module.exports = {
root: true,
parser: "@typescript-eslint/parser",
parserOptions: {
ecmaVersion: 2020,
sourceType: "module"
},
settings: {
react: {
version: "detect"
}
},
env: {
es2021: true,
browser: true
},
plugins: ["@typescript-eslint", "react", "react-hooks"],
extends: [
"eslint:recommended",
"plugin:react/recommended",
"plugin:@typescript-eslint/recommended",
"plugin:react-hooks/recommended",
"prettier"
]
};

7
shared/ui/.prettierrc Normal file
View File

@@ -0,0 +1,7 @@
{
"singleQuote": false,
"trailingComma": "all",
"tabWidth": 2,
"printWidth": 90,
"semi": true
}

28
shared/ui/package.json Normal file
View File

@@ -0,0 +1,28 @@
{
"name": "@family-planner/ui",
"version": "0.1.0",
"private": true,
"type": "module",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"build": "tsc -p tsconfig.json",
"lint": "eslint \"src/**/*.{ts,tsx}\" --max-warnings=0",
"format": "prettier --write \"src/**/*.{ts,tsx}\""
},
"peerDependencies": {
"react": "^18.3.0",
"react-dom": "^18.3.0",
"styled-components": "^6.1.0"
},
"devDependencies": {
"typescript": "^5.6.0",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"eslint": "^9.0.0",
"@typescript-eslint/parser": "^7.0.0",
"@typescript-eslint/eslint-plugin": "^7.0.0",
"eslint-config-prettier": "^9.0.0",
"prettier": "^3.3.0"
}
}

View File

@@ -0,0 +1,24 @@
import { jsx as _jsx } from "react/jsx-runtime";
import styled from "styled-components";
const StyledButton = styled.button `
padding: 10px 18px;
border-radius: 12px;
font-weight: 600;
border: none;
cursor: pointer;
transition: transform 0.2s ease, box-shadow 0.2s ease;
background: ${({ variant }) => {
if (variant === "secondary")
return "rgba(93, 132, 255, 0.16)";
if (variant === "ghost")
return "transparent";
return "linear-gradient(135deg, #5562ff, #7d6cff)";
}};
color: ${({ variant }) => (variant === "ghost" ? "#f0f3ff" : "#ffffff")};
box-shadow: ${({ variant }) => variant === "ghost" ? "none" : "0 14px 30px rgba(85, 98, 255, 0.25)"};
&:hover {
transform: translateY(-1px);
}
`;
export const Button = ({ variant = "primary", ...props }) => (_jsx(StyledButton, { variant: variant, ...props }));

View File

@@ -0,0 +1,30 @@
import styled from "styled-components";
export type ButtonProps = React.ButtonHTMLAttributes<HTMLButtonElement> & {
variant?: "primary" | "secondary" | "ghost";
};
const StyledButton = styled.button<ButtonProps>`
padding: 10px 18px;
border-radius: 12px;
font-weight: 600;
border: none;
cursor: pointer;
transition: transform 0.2s ease, box-shadow 0.2s ease;
background: ${({ variant }) => {
if (variant === "secondary") return "rgba(93, 132, 255, 0.16)";
if (variant === "ghost") return "transparent";
return "linear-gradient(135deg, #5562ff, #7d6cff)";
}};
color: ${({ variant }) => (variant === "ghost" ? "#f0f3ff" : "#ffffff")};
box-shadow: ${({ variant }) =>
variant === "ghost" ? "none" : "0 14px 30px rgba(85, 98, 255, 0.25)"};
&:hover {
transform: translateY(-1px);
}
`;
export const Button = ({ variant = "primary", ...props }: ButtonProps) => (
<StyledButton variant={variant} {...props} />
);

View File

@@ -0,0 +1,10 @@
import styled from "styled-components";
export const Card = styled.div `
padding: 20px 24px;
border-radius: 18px;
background: rgba(29, 36, 66, 0.92);
border: 1px solid rgba(126, 136, 180, 0.22);
display: flex;
flex-direction: column;
gap: 16px;
`;

View File

@@ -0,0 +1,11 @@
import styled from "styled-components";
export const Card = styled.div`
padding: 20px 24px;
border-radius: 18px;
background: rgba(29, 36, 66, 0.92);
border: 1px solid rgba(126, 136, 180, 0.22);
display: flex;
flex-direction: column;
gap: 16px;
`;

View File

@@ -0,0 +1,6 @@
import styled from "styled-components";
export const SectionTitle = styled.h2 `
margin: 0;
font-size: 1.4rem;
font-weight: 600;
`;

View File

@@ -0,0 +1,7 @@
import styled from "styled-components";
export const SectionTitle = styled.h2`
margin: 0;
font-size: 1.4rem;
font-weight: 600;
`;

3
shared/ui/src/index.js Normal file
View File

@@ -0,0 +1,3 @@
export * from './components/Button';
export * from './components/Card';
export * from './components/SectionTitle';

3
shared/ui/src/index.ts Normal file
View File

@@ -0,0 +1,3 @@
export * from './components/Button';
export * from './components/Card';
export * from './components/SectionTitle';

16
shared/ui/tsconfig.json Normal file
View File

@@ -0,0 +1,16 @@
{
"compilerOptions": {
"declaration": true,
"declarationMap": true,
"emitDeclarationOnly": false,
"module": "ESNext",
"target": "ES2020",
"moduleResolution": "Node",
"outDir": "dist",
"rootDir": "src",
"jsx": "react-jsx",
"strict": true,
"esModuleInterop": true
},
"include": ["src"]
}