diff --git a/.development/.dockerignore b/.development/.dockerignore new file mode 100644 index 0000000..564d233 --- /dev/null +++ b/.development/.dockerignore @@ -0,0 +1,62 @@ +# ============================================================================== +# .dockerignore - Excludes files from Docker build context +# ============================================================================== +# This file prevents unnecessary files from being sent to Docker daemon +# during image builds, speeding up the build process and reducing image size. +# +# Note: Source code is bind-mounted at runtime, not copied during build, +# so this primarily affects base image creation. +# ============================================================================== + +# Version control +.git +.gitignore + +# Dependencies (installed in container at runtime) +node_modules +**/node_modules + +# Build outputs (generated in container) +build +**/build +dist +**/dist +*.tsbuildinfo + +# Environment files (mounted separately per service) +# Exclude all .env files except development ones +.env +.env.* +packages/**/.env +packages/**/.env.* + +# Keep development environment files (needed for Docker builds) +!.development/packages/**/.env + +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +pnpm-debug.log* + +# IDE and editor files +.vscode +.idea +*.swp +*.swo +*~ +.DS_Store + +# Testing +coverage +.nyc_output + +# Misc +.cache +*.tgz +.npmrc +.continue + +# Keep .development folder (needed for entrypoint scripts) +!.development diff --git a/.development/.gitignore b/.development/.gitignore new file mode 100644 index 0000000..1198234 --- /dev/null +++ b/.development/.gitignore @@ -0,0 +1,17 @@ +# ============================================================================== +# .gitignore - Keep only source files in Git +# ============================================================================== +# This configuration ensures only configuration files are tracked. +# Runtime files and generated content stay in Docker volumes. +# ============================================================================== + +# Ignore all files by default +!* + +# Track only these specific patterns: +# - .env files (development environment variables) +# - Dockerfiles (service image definitions) +# - entrypoint.sh scripts (container startup scripts) +# - compose.yml (docker compose configuration) +# - .dockerignore (build context exclusions) +# - .gitignore (this file) diff --git a/.development/README.md b/.development/README.md new file mode 100644 index 0000000..c66707b --- /dev/null +++ b/.development/README.md @@ -0,0 +1,153 @@ +# Development Environment + +Docker-based development environment for the Arrhes platform. + +## Architecture + +``` +.development/ +├── compose.yml # Main Docker Compose configuration +├── .dockerignore # Build context exclusions +├── .gitignore # Git tracking rules +└── packages/ + ├── api/ + │ ├── Dockerfile # API service image + │ ├── entrypoint.sh # API startup script + │ └── .env # API environment variables + ├── dashboard/ + │ ├── Dockerfile # Dashboard service image + │ ├── entrypoint.sh # Dashboard startup script + │ └── .env # Dashboard environment variables + ├── tools/ + │ └── .env # Tools environment variables + └── website/ + ├── Dockerfile # Website service image + ├── entrypoint.sh # Website startup script + └── .env # Website environment variables +``` + +## Key Concepts + +### Source Code Binding +- **Source files** (packages/) are bind-mounted from host to container +- Changes made on **either host or container** are instantly synced +- Enables live editing with IDE on host and HMR in container + +### Runtime Isolation +- **node_modules** stored in Docker volumes (not on host) +- **Build outputs** stored in Docker volumes +- Keeps host clean and ensures consistent dependencies + +### Services + +**Infrastructure:** +- PostgreSQL (port 5432) - Database +- RustFS (ports 9000, 9001) - S3-compatible storage +- Mailpit (ports 1025, 8025) - SMTP server with web UI + +**Applications:** +- API (port 3000) - Hono backend +- Dashboard (port 5173) - React admin interface +- Website (port 5174) - React public site + +## Usage + +### Start all services +```bash +# Create required volumes first +docker volume create arrhes_postgres_data +docker volume create arrhes_rustfs_data + +# Start services +docker compose -f .development/compose.yml up -d +``` + +### View logs +```bash +# All services +docker compose -f .development/compose.yml logs -f + +# Specific service +docker compose -f .development/compose.yml logs -f api +``` + +### Stop services +```bash +docker compose -f .development/compose.yml down +``` + +### Rebuild after changes +```bash +# Rebuild specific service +docker compose -f .development/compose.yml build api + +# Rebuild and restart +docker compose -f .development/compose.yml up -d --build api +``` + +### Access running containers +```bash +docker compose -f .development/compose.yml exec api bash +``` + +## Environment Files + +Each service has its own `.env` file in `.development/packages/{service}/.env`: + +- **api/.env** - API configuration (database, storage, email) +- **dashboard/.env** - Dashboard configuration (API URL) +- **website/.env** - Website configuration (API URL) +- **tools/.env** - Database tools configuration + +These files are bind-mounted into containers at runtime. + +## How It Works + +1. **Build Phase:** + - Dockerfiles create minimal base images with Node.js + PNPM + - No source code or dependencies copied during build + - Images are lightweight and reusable + +2. **Runtime Phase:** + - Source code bind-mounted from `../packages` to `/workspace/packages` + - node_modules stored in named volumes (isolated per service) + - Entrypoint scripts install dependencies and start dev servers + +3. **Development:** + - Edit code on host with your IDE + - Changes instantly reflected in container + - Vite HMR updates browser automatically + - No manual restarts needed + +## Troubleshooting + +### Port already in use +```bash +# Check what's using the port +lsof -i :3000 + +# Stop the conflicting service or change port in compose.yml +``` + +### Dependencies not updating +```bash +# Remove volume and rebuild +docker volume rm .dev_api_node_modules +docker compose -f .development/compose.yml up -d --build api +``` + +### Database reset +```bash +# Remove database volume (WARNING: deletes all data) +docker compose -f .development/compose.yml down +docker volume rm arrhes_postgres_data +docker volume create arrhes_postgres_data +docker compose -f .development/compose.yml up -d +``` + +### Clean slate +```bash +# Remove all containers, volumes (except external), and rebuild +docker compose -f .development/compose.yml down -v +docker compose -f .development/compose.yml up -d --build +``` diff --git a/.development/compose.yml b/.development/compose.yml new file mode 100644 index 0000000..a460082 --- /dev/null +++ b/.development/compose.yml @@ -0,0 +1,151 @@ +# ============================================================================== +# Arrhes Platform - Development Environment +# ============================================================================== +# Docker Compose configuration for local development +# +# Architecture: +# - Source code: bind-mounted from host (live editing on both host and container) +# - Runtime files: isolated in Docker volumes (node_modules, build outputs) +# - Infrastructure: PostgreSQL, RustFS (S3), Mailpit (SMTP) +# - Services: API, Dashboard, Website +# +# Usage: +# docker compose -f .development/compose.yml up -d # Start all services +# docker compose -f .development/compose.yml down # Stop all services +# docker compose -f .development/compose.yml logs -f # View logs +# ============================================================================== + +services: + # ============================================================================ + # Infrastructure Services + # ============================================================================ + + # PostgreSQL - Relational database for application data + postgres: + image: postgres:18.1 + restart: unless-stopped + environment: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: admin + POSTGRES_DB: default + ports: + - "5432:5432" + volumes: + - postgres_data:/var/lib/postgresql + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres -d default"] + interval: 10s + timeout: 5s + retries: 5 + + # RustFS - S3-compatible object storage for attachments/files + rustfs: + image: rustfs/rustfs:latest + restart: unless-stopped + environment: + RUSTFS_CONSOLE_ENABLE: true + RUSTFS_ACCESS_KEY: rustfsadmin + RUSTFS_SECRET_KEY: rustfsadmin + RUSTFS_VOLUMES: /data + ports: + - "9000:9000" # API + - "9001:9001" # Web Console + volumes: + - rustfs_data:/data + init: true + healthcheck: + test: ["CMD-SHELL", "wget --quiet --tries=1 --spider http://localhost:9000 2>&1 | grep -q '403 Forbidden' && exit 0 || exit 1"] + interval: 10s + timeout: 5s + retries: 5 + + # Mailpit - Development SMTP server with web interface + mailpit: + image: axllent/mailpit:latest + restart: unless-stopped + ports: + - "1025:1025" # SMTP + - "8025:8025" # Web UI + healthcheck: + test: ["CMD-SHELL", "wget --quiet --tries=1 --spider http://localhost:8025 || exit 1"] + interval: 10s + timeout: 5s + retries: 5 + + # ============================================================================ + # Application Services + # ============================================================================ + + # API - Backend service (Hono framework on Node.js) + api: + build: + context: .. + dockerfile: .development/packages/api/Dockerfile + args: + NODE_VERSION: "25.2.1" + PNPM_VERSION: "10.26.1" + ports: + - "3000:3000" # API server + volumes: + # Source code - bind-mounted for live editing (synced between host and container) + - ../packages:/workspace/packages:cached + - ../package.json:/workspace/package.json:cached + - ../pnpm-workspace.yaml:/workspace/pnpm-workspace.yaml:cached + - ../pnpm-lock.yaml:/workspace/pnpm-lock.yaml:cached + - ../.development:/workspace/.development:cached + + # Environment files - use .development versions + - ./packages/api/.env:/workspace/packages/api/.env:cached + - ./packages/tools/.env:/workspace/packages/tools/.env:cached + + # Runtime files - isolated in Docker volumes (NOT on host) + - api_node_modules:/workspace/node_modules + - metadata_build:/workspace/packages/metadata/build + - pnpm_store:/root/.local/share/pnpm/store + depends_on: + postgres: + condition: service_healthy + rustfs: + condition: service_healthy + mailpit: + condition: service_healthy + + # Dashboard - Frontend admin interface (React + Vite) + dashboard: + build: + context: .. + dockerfile: .development/packages/dashboard/Dockerfile + args: + NODE_VERSION: "25.2.1" + PNPM_VERSION: "10.26.1" + ports: + - "5173:5173" # Vite dev server + volumes: + # Source code only - bind-mounted for live editing + # node_modules and metadata/build stay inside the image (installed at build time) + - ../packages/dashboard/src:/workspace/packages/dashboard/src:cached + - ../packages/dashboard/public:/workspace/packages/dashboard/public:cached + - ../packages/dashboard/vite.config.ts:/workspace/packages/dashboard/vite.config.ts:cached + - ../packages/dashboard/tsconfig.json:/workspace/packages/dashboard/tsconfig.json:cached + - ../packages/dashboard/panda.config.ts:/workspace/packages/dashboard/panda.config.ts:cached + # Shared UI package for live editing + - ../packages/ui/src:/workspace/packages/ui/src:cached + - ../packages/ui/tsconfig.json:/workspace/packages/ui/tsconfig.json:cached + - ../packages/ui/panda.config.ts:/workspace/packages/ui/panda.config.ts:cached + +# ============================================================================== +# Named Volumes (Runtime data isolated from host) +# ============================================================================== +volumes: + # Application runtime dependencies - isolated per service + api_node_modules: + + # Shared build output - metadata package used by multiple services + metadata_build: + + # PNPM global store cache - shared across all Node services for efficiency + pnpm_store: + + # Persistent infrastructure data - survives container restarts + postgres_data: + rustfs_data: diff --git a/.development/packages/api/.env b/.development/packages/api/.env new file mode 100644 index 0000000..c1c1db5 --- /dev/null +++ b/.development/packages/api/.env @@ -0,0 +1,28 @@ +# Environment +ENV="development" +VERBOSE="true" +PORT="3000" + +# CORS and Cookies +CORS_ORIGIN="http://localhost:5173" +COOKIES_DOMAIN="localhost" +COOKIES_KEY="development-secret-key-change-in-production-min-32-chars" + +# URLs +API_BASE_URL="http://localhost:3000" +PLATFORM_BASE_URL="http://localhost:5173" +WEBSITE_BASE_URL="http://localhost:5174" + +# Database (Docker Compose) +SQL_DATABASE_URL="postgres://postgres:admin@postgres:5432/default" + +# Storage (RustFS via Docker Compose) +STORAGE_ENDPOINT="http://rustfs:9000" +STORAGE_BUCKET_NAME="arrhes-files" +STORAGE_ACCESS_KEY="rustfsadmin" +STORAGE_SECRET_KEY="rustfsadmin" + +# Email Mailpit (Docker Compose) +EMAIL_ENDPOINT="mailpit:1025" +EMAIL_USER="test" +EMAIL_PASSWORD="test" diff --git a/.development/packages/api/Dockerfile b/.development/packages/api/Dockerfile new file mode 100644 index 0000000..3b0804d --- /dev/null +++ b/.development/packages/api/Dockerfile @@ -0,0 +1,25 @@ +# ============================================================================== +# API Service Dockerfile +# ============================================================================== +# Creates a Node.js container with PNPM for running the API service +# Source code is bind-mounted from host, dependencies installed at runtime +# ============================================================================== + +ARG NODE_VERSION="25.2.1" +ARG PNPM_VERSION="10.26.1" + +FROM node:${NODE_VERSION}-bullseye-slim + +# Install PNPM package manager, PostgreSQL client, and expect +RUN npm install -g "pnpm@${PNPM_VERSION}" && \ + apt-get update && \ + apt-get install -y postgresql-client expect && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* + +# Set working directory +WORKDIR /workspace + +# Start via entrypoint script (bind-mounted at runtime) +# NOTE: We don't switch to node user here - entrypoint will handle permissions +ENTRYPOINT ["/bin/bash", "/workspace/.development/packages/api/entrypoint.sh"] diff --git a/.development/packages/api/build.sh b/.development/packages/api/build.sh new file mode 100644 index 0000000..a650e3d --- /dev/null +++ b/.development/packages/api/build.sh @@ -0,0 +1,10 @@ +#!/bin/bash +# ============================================================================== +# Build Metadata Package +# ============================================================================== +# Builds the metadata package which is required by API and tools +# ============================================================================== +set -e + +echo "🔨 Building @arrhes/application-metadata..." +pnpm --filter="@arrhes/application-metadata" build diff --git a/.development/packages/api/entrypoint.sh b/.development/packages/api/entrypoint.sh new file mode 100644 index 0000000..e75b710 --- /dev/null +++ b/.development/packages/api/entrypoint.sh @@ -0,0 +1,23 @@ +#!/bin/bash +# ============================================================================== +# API Service Entrypoint +# ============================================================================== +# Runs on container startup to initialize and start the API service +# Calls individual scripts for each task +# ============================================================================== +set -e + +SCRIPT_DIR="/workspace/.development/packages/api" + +# Fix permissions for bind-mounted workspace +echo "🔧 Fixing workspace permissions..." +chown -R node:node /workspace + +# Run all setup tasks as node user +su node -c "$SCRIPT_DIR/install.sh" +su node -c "$SCRIPT_DIR/build.sh" +su node -c "$SCRIPT_DIR/migrate.sh" +su node -c "$SCRIPT_DIR/seed.sh" + +# Start the API server (exec replaces shell process) +exec su node -c "$SCRIPT_DIR/start.sh" diff --git a/.development/packages/api/install.sh b/.development/packages/api/install.sh new file mode 100644 index 0000000..826b57a --- /dev/null +++ b/.development/packages/api/install.sh @@ -0,0 +1,10 @@ +#!/bin/bash +# ============================================================================== +# Install Dependencies +# ============================================================================== +# Installs all workspace dependencies using PNPM +# ============================================================================== +set -e + +echo "📦 Installing workspace dependencies..." +pnpm install --no-frozen-lockfile diff --git a/.development/packages/api/migrate.sh b/.development/packages/api/migrate.sh new file mode 100644 index 0000000..23df81e --- /dev/null +++ b/.development/packages/api/migrate.sh @@ -0,0 +1,35 @@ +#!/bin/bash +# ============================================================================== +# Database Migration +# ============================================================================== +# Runs database migrations using Drizzle +# Checks if tables exist before running to avoid unnecessary migrations +# ============================================================================== +set -e + +echo "🗄️ Checking database..." + +# Check if tables already exist +if PGPASSWORD=admin psql -h postgres -U postgres -d default -c '\dt' 2>/dev/null | grep -q table_user; then + echo "✓ Database tables already exist, skipping migration" +else + echo "Running database migrations..." + cd /workspace/packages/tools + # Use expect to handle interactive prompts - select first option (no truncate) + expect -c ' + set timeout 60 + spawn pnpm run push + expect { + "No, add the constraint without truncating the table" { + send "\r" + exp_continue + } + "No, abort" { + send "\r" + exp_continue + } + eof + } + ' || true + echo "✓ Database migrations complete" +fi diff --git a/.development/packages/api/seed.sh b/.development/packages/api/seed.sh new file mode 100644 index 0000000..aa19bdf --- /dev/null +++ b/.development/packages/api/seed.sh @@ -0,0 +1,12 @@ +#!/bin/bash +# ============================================================================== +# Seed Demo Data +# ============================================================================== +# Seeds the database with demo data for development +# ============================================================================== +set -e + +echo "🌱 Seeding demo data..." +cd /workspace/packages/tools +pnpm run seed || echo "Seeding skipped (data may already exist)" +echo "✓ Seeding complete" diff --git a/.development/packages/api/start.sh b/.development/packages/api/start.sh new file mode 100644 index 0000000..198d320 --- /dev/null +++ b/.development/packages/api/start.sh @@ -0,0 +1,11 @@ +#!/bin/bash +# ============================================================================== +# Start API Server +# ============================================================================== +# Starts the API development server with hot reload +# ============================================================================== +set -e + +echo "🚀 Starting API dev server..." +cd /workspace/packages/api +exec pnpm --filter="@arrhes/application-api" dev diff --git a/.development/packages/dashboard/.env b/.development/packages/dashboard/.env new file mode 100644 index 0000000..3e58450 --- /dev/null +++ b/.development/packages/dashboard/.env @@ -0,0 +1,4 @@ +VITE_ENV="development" +VITE_API_BASE_URL=http://localhost:3000 +VITE_DASHBOARD_BASE_URL=http://localhost:5173 +VITE_WEBSITE_BASE_URL=http://localhost:5174 diff --git a/.development/packages/dashboard/Dockerfile b/.development/packages/dashboard/Dockerfile new file mode 100644 index 0000000..08df38f --- /dev/null +++ b/.development/packages/dashboard/Dockerfile @@ -0,0 +1,50 @@ +# ============================================================================== +# Dashboard Development Dockerfile +# ============================================================================== +# Self-contained development image for the dashboard service. +# - Dependencies installed at build time (node_modules inside image) +# - Source code bind-mounted at runtime for live editing +# - No entrypoint script needed - just run `docker compose up` +# ============================================================================== + +ARG NODE_VERSION="25.2.1" +ARG PNPM_VERSION="10.26.1" + +FROM node:${NODE_VERSION}-bullseye-slim + +ARG PNPM_VERSION + +# Install PNPM +RUN npm install -g "pnpm@${PNPM_VERSION}" && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* + +WORKDIR /workspace + +# Copy package manifests for dependency installation +COPY package.json pnpm-workspace.yaml ./ + +COPY packages/metadata ./packages/metadata +COPY packages/ui ./packages/ui +COPY packages/dashboard ./packages/dashboard + +# Install all dependencies (hoisted to workspace root) +RUN pnpm install + + +# Copy metadata source and build it (dashboard depends on it) +RUN pnpm --filter="@arrhes/application-metadata" build + +RUN pnpm --filter="@arrhes/dashboard" run prepare + +# RUN pnpm --filter="@arrhes/ui" build + +# Copy environment file for Vite +COPY .development/packages/dashboard/.env ./packages/dashboard/.env + +# Set working directory to dashboard package +WORKDIR /workspace/packages/dashboard + +# Run Vite dev server +# Source files will be bind-mounted at runtime, overriding the copied files +CMD ["pnpm", "dev", "--", "--host", "0.0.0.0"] diff --git a/.development/packages/tools/.env b/.development/packages/tools/.env new file mode 100644 index 0000000..c2697d4 --- /dev/null +++ b/.development/packages/tools/.env @@ -0,0 +1,2 @@ +NODE_ENV="development" +SQL_DATABASE_URL="postgres://postgres:admin@postgres:5432/default" diff --git a/.gitignore b/.gitignore index 0a523f4..532c479 100644 --- a/.gitignore +++ b/.gitignore @@ -5,9 +5,12 @@ build .env .npmrc .continue -.dev .old .vscode pnpm-lock.yaml -*.tsbuildinfo \ No newline at end of file +.pnpm-store + +*.tsbuildinfo + +styled-system \ No newline at end of file diff --git a/.old.env b/.old.env new file mode 100644 index 0000000..c541bcf --- /dev/null +++ b/.old.env @@ -0,0 +1,22 @@ +ENV="development" +VERBOSE="true" +PORT="3000" + +CORS_ORIGIN="http://localhost:3101,http://localhost:3102" +COOKIES_DOMAIN="localhost" +COOKIES_KEY="nLR54unTYqW%Pn" + +API_BASE_URL="http://localhost:3100" +PLATFORM_BASE_URL="http://localhost:3101" +WEBSITE_BASE_URL="https//localhost:3102" + +SQL_DATABASE_URL="postgres://development:76KeGDObGLjzn1s12&@195.154.70.77:20960/development" + +STORAGE_ENDPOINT="https://s3.fr-par.scw.cloud" +STORAGE_BUCKET_NAME="arrhes.development" +STORAGE_ACCESS_KEY="SCW0MY50MZT3B2HHZM1K" +STORAGE_SECRET_KEY="11126f13-73bf-4c42-b555-4a8108bb2c82" + +EMAIL_ENDPOINT="smtp.tem.scw.cloud" +EMAIL_USER="17d4af36-78b5-4175-8b2b-8f8c497b616b" +EMAIL_PASSWORD="c37e79af-2b9e-4e44-9d21-ce22526d8fa0" \ No newline at end of file diff --git a/.production/.gitignore b/.production/.gitignore new file mode 100644 index 0000000..244ed9f --- /dev/null +++ b/.production/.gitignore @@ -0,0 +1,17 @@ +# ============================================================================== +# .gitignore - Keep only source files in Git +# ============================================================================== +# This configuration ensures only configuration files are tracked. +# Runtime files and generated content stay in Docker volumes. +# ============================================================================== + +# Ignore all files by default +!* + +# Track only these specific patterns: +# - .env files (development environment variables) +# - Dockerfiles (service image definitions) +# - entrypoint.sh scripts (container startup scripts) +# - compose.yml (docker compose configuration) +# - .dockerignore (build context exclusions) +# - .gitignore (this file) diff --git a/.production/compose.yml b/.production/compose.yml new file mode 100644 index 0000000..e69de29 diff --git a/packages/api/.docker/.dockerignore b/.production/packages/api/.dockerignore similarity index 100% rename from packages/api/.docker/.dockerignore rename to .production/packages/api/.dockerignore diff --git a/.production/packages/api/.env b/.production/packages/api/.env new file mode 100644 index 0000000..0953a27 --- /dev/null +++ b/.production/packages/api/.env @@ -0,0 +1,28 @@ +# Environment +ENV=development +VERBOSE=true +PORT=3000 + +# CORS and Cookies +CORS_ORIGIN=http://localhost:5173 +COOKIES_DOMAIN=localhost +COOKIES_KEY=development-secret-key-change-in-production-min-32-chars + +# URLs +API_BASE_URL=http://localhost:3000 +PLATFORM_BASE_URL=http://localhost:5173 +WEBSITE_BASE_URL=http://localhost:5174 + +# Database (Docker Compose service names) +SQL_DATABASE_URL=postgres://postgres:admin@postgres:5432/default + +# Storage (RustFS service) +STORAGE_ENDPOINT=http://rustfs:9000 +STORAGE_BUCKET_NAME=arrhes-files +STORAGE_ACCESS_KEY=rustfsadmin +STORAGE_SECRET_KEY=rustfsadmin + +# Email (Mailpit) +EMAIL_ENDPOINT=mailpit:1025 +EMAIL_USER=test +EMAIL_PASSWORD=test diff --git a/packages/api/.docker/Dockerfile b/.production/packages/api/Dockerfile similarity index 100% rename from packages/api/.docker/Dockerfile rename to .production/packages/api/Dockerfile diff --git a/packages/platform/.docker/.dockerignore b/.production/packages/dashboard/.dockerignore similarity index 100% rename from packages/platform/.docker/.dockerignore rename to .production/packages/dashboard/.dockerignore diff --git a/.production/packages/dashboard/.env b/.production/packages/dashboard/.env new file mode 100644 index 0000000..2854814 --- /dev/null +++ b/.production/packages/dashboard/.env @@ -0,0 +1,5 @@ +NODE_ENV="development" +VITE_ENV="development" +VITE_PUBLIC_API_URL="http://localhost:3100" +VITE_PUBLIC_PLATFORM_URL="http://localhost:3101" +VITE_PUBLIC_WEBSITE_URL="http://localhost:3102" diff --git a/packages/platform/.docker/Dockerfile b/.production/packages/dashboard/Dockerfile similarity index 100% rename from packages/platform/.docker/Dockerfile rename to .production/packages/dashboard/Dockerfile diff --git a/packages/platform/.docker/nginx/default.conf b/.production/packages/dashboard/nginx/default.conf similarity index 100% rename from packages/platform/.docker/nginx/default.conf rename to .production/packages/dashboard/nginx/default.conf diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..89795c7 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,24 @@ +# Agent Guidelines + +## Commands +- Build all: `pnpm build` — Dev all: `pnpm dev` — Docker: `just dev up` / `just dev down` / `just dev reset` +- Lint dashboard: `pnpm --filter @arrhes/application-dashboard run lint` +- Typecheck dashboard: `packages/dashboard/node_modules/.bin/tsc --noEmit --project packages/dashboard/tsconfig.json` +- No test framework exists in this repository. + +## Monorepo Layout +`packages/{api, dashboard, metadata, tools, ui}` — all ESM (`"type": "module"`), TypeScript strict mode. +- **api** (`@arrhes/application-api`): Hono backend, Drizzle ORM, PostgreSQL, Nodemailer, Puppeteer, S3 +- **dashboard** (`@arrhes/application-dashboard`): React 19, TanStack Router/Query/Table, React Hook Form, Radix UI primitives, Panda CSS +- **metadata** (`@arrhes/application-metadata`): Shared models, schemas (valibot), route definitions. Consumed via subpath exports (`@arrhes/application-metadata/models`, `/schemas`, `/routes`, `/components`) +- **ui** (`@arrhes/ui`): Shared components/styles/fonts using Panda CSS. Consumed via `@arrhes/ui`, `@arrhes/ui/utilities/cn.js`, `@arrhes/ui/styled-system/css` +- **tools** (`@arrhes/application-tools`): DB migrations/seeds via drizzle-kit and tsx scripts + +## Code Style +- **Imports**: all use relative paths with `.ts`/`.tsx` extensions (dashboard) or `.js` extensions (api, metadata). Cross-package via `@arrhes/*`. No path aliases are used in practice. Order: workspace packages → external deps → relative internal. +- **Files**: all `camelCase.ts[x]` (including components). Barrel files are `_index.ts`. +- **Exports**: components `PascalCase` functions, models/schemas/utilities `camelCase`. Models use `Model` suffix (`accountModel`), schemas have no suffix. +- **Validation**: `import * as v from "valibot"` — use `v.object()`, `v.string()`, `v.InferOutput<>`. +- **Styling**: Panda CSS via `css()` and `cx()` from `@arrhes/ui/utilities/cn.js`. +- **IDs**: nanoid with custom alphabet, 16 chars. +- **Error handling**: try/catch with structured logging in API; toast notifications in dashboard; structured error responses via Hono. diff --git a/LICENSE b/LICENSE index b7f2345..1b19e53 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,661 @@ -MIT License - -Copyright (c) 2025 Arrhes - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + Arrhes - Open source double-entry accounting for French associations and SMEs. + Copyright (C) 2025 Arrhes + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. diff --git a/README.md b/README.md index 2f58607..5b43fbd 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,173 @@ -## Description +# Arrhes + +[![Licence MIT](https://img.shields.io/badge/licence-MIT-blue.svg)](LICENSE) +[![TypeScript](https://img.shields.io/badge/TypeScript-5.9-blue.svg)](https://www.typescriptlang.org/) +[![Node.js](https://img.shields.io/badge/Node.js-24.5-green.svg)](https://nodejs.org/) Application **open source** de gestion de comptabilité en partie double pour les associations et entreprises françaises. Elle permet de configurer les comptes, d'ajouter les écritures comptables, les pièces justificatives et de consulter les différents états financiers tels que le bilan ou le compte de résultat. +## Table des matières + +- [À propos](#à-propos) +- [Fonctionnalités](#fonctionnalités) +- [Démarrage rapide](#démarrage-rapide) +- [Documentation](#documentation) +- [Licence](#licence) +- [Support](#support) + +## À propos + +Arrhes est une solution complète de comptabilité conçue spécifiquement pour répondre aux besoins des associations et entreprises françaises. L'application adopte une architecture monorepo et une interface utilisateur simple et intuitive. + +**Public cible :** +- Associations loi 1901 +- Petites et moyennes entreprises +- Comptables et experts-comptables +- Trésoriers d'associations ## Fonctionnalités -- Configuration des comptes -- Création et gestion des écritures comptables -- Gestion des pièces justificatives -- Configuration et consultation des états financiers (bilan, compte de résultat, etc.) -- Gestion des exercices comptables -- Gestion des utilisateurs et des rôles +- ✅ Configuration et gestion des comptes comptables +- ✅ Création et gestion des écritures comptables en partie double +- ✅ Gestion des pièces justificatives avec stockage sécurisé +- ✅ Configuration et consultation des états financiers (bilan, compte de résultat) +- ✅ Gestion des exercices comptables +- ✅ Gestion multi-utilisateurs avec rôles et permissions +- ✅ Authentification sécurisée par magic link +- ✅ Support des journaux comptables multiples +- ✅ Calculs automatiques et validation des écritures + +## Démarrage rapide + +### Option 1 : Dev Container 🚀 (Le plus simple) + +Prérequis : Docker + +Quick CLI workflow (no editor integration required): + +```bash +# Clone & enter repo +git clone https://github.com/arrhes/arrhes-application.git +cd arrhes-application + +# Start the devcontainer services (bind-mounts your workspace) +./devcontainer-start.sh + +# Bootstrap the workspace (run inside the devcontainer): installs deps, builds metadata, pushes schema and seeds DB +./dev/scripts/initialize.sh + +# Open an interactive shell inside the devcontainer (one-line) +docker compose -f .development/compose.yml exec devcontainer bash + +# From that shell you can start the dev servers (they must bind to 0.0.0.0 to be reachable from the host): +# API +pnpm --filter api run dev +# Platform (Vite) - ensure host binding +pnpm --filter platform run dev -- --host +# Website (Vite) - ensure host binding +pnpm --filter website run dev -- --host +``` + +If you prefer to attach VS Code to the running container instead of using an in-container shell, install the "Dev Containers" extension and use "Dev Containers: Attach to Running Container..." then select the `devcontainer` container. Edits are persisted on the host because the service mount `.:/workspace` is a bind mount. + + + +Tout est configuré automatiquement : Node.js, pnpm, PostgreSQL, RustFS, MailHog, et les données de démonstration ! + +### Option 2 : Avec Docker Compose 🐳 + +Prérequis : Node.js 24.5+, pnpm, Docker + +```bash +# Cloner le repository +git clone https://github.com/arrhes/arrhes-application.git +cd arrhes-application + +# Installer les dépendances +pnpm install + +# Lancer les services (PostgreSQL, RustFS, MailHog) +docker-compose up -d + +# Créer le bucket RustFS +# Accéder à http://localhost:9001 (arrhes_rustfs / arrhes_rustfs_secret) +# Créer un bucket nommé "arrhes-files" +# Configurer les variables d'environnement +# Créer packages/api/.env et packages/tools/.env +# (voir la documentation complète) + +# Initialiser la base de données +pnpm --filter tools run push +pnpm --filter tools run seed + +# Lancer l'application +pnpm run dev +``` + +### Option 3 : Installation native + +Prérequis : Node.js 24.5+, pnpm, PostgreSQL + +```bash +# Cloner le repository +git clone https://github.com/arrhes/arrhes-application.git +cd arrhes-application + +# Installer les dépendances +pnpm install + +# Créer la base de données PostgreSQL +# (voir la documentation complète) + +# Configurer les variables d'environnement +# Créer packages/api/.env et packages/tools/.env +# (voir la documentation complète) + +# Initialiser la base de données +pnpm --filter tools run push +pnpm --filter tools run seed + +# Lancer l'application +pnpm run dev +``` + +L'API sera accessible sur `http://localhost:3101`, la plateforme sur `http://localhost:3101` et le website sur `http://localhost:3102. + +**Identifiants de démonstration :** `demo@arrhes.com` / `demo` + +**Pour plus de détails, consultez le [Guide de développement](docs/DEVELOPMENT.md).** + +## Documentation + +- 📚 [Architecture](docs/ARCHITECTURE.md) - Vue d'ensemble de l'architecture et du stack technique +- ⚙️ [Configuration](docs/CONFIGURATION.md) - Variables d'environnement et configuration des services +- 🛠️ [Développement](docs/DEVELOPMENT.md) - Guide complet pour les développeurs +- 🤝 [Contribution](docs/CONTRIBUTING.md) - Guidelines pour contribuer au projet ## Packages -- API -- metadata -- platform -- tools +Le projet est organisé en monorepo avec les packages suivants : + +- **@arrhes/api** - Backend REST API (Hono, PostgreSQL) +- **@arrhes/platform** - Interface web (React, TanStack Router) +- **@arrhes/application-metadata** - Schémas et modèles partagés (Valibot, Drizzle ORM) +- **@arrhes/tools** - Outils de migration et seed de base de données +- **@arrhes/website** - Site vitrine + Documentation + +Pour plus de détails, consultez la [documentation d'architecture](docs/ARCHITECTURE.md). + +## Licence + +Ce projet est sous licence MIT. Voir le fichier [LICENSE](LICENSE) pour plus de détails. + +## Support + +- 🐛 [Signaler un bug](https://github.com/arrhes/arrhes-application/issues) +- 💡 [Proposer une fonctionnalité](https://github.com/arrhes/arrhes-application/issues) +- 📧 Contact : contact@arrhes.com + +--- + +Développé avec ❤️ pour la communauté française + diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md new file mode 100644 index 0000000..1832dc8 --- /dev/null +++ b/docs/ARCHITECTURE.md @@ -0,0 +1,537 @@ +# Architecture + +Ce document décrit l'architecture globale du projet Arrhes, un système de comptabilité en partie double pour associations et entreprises françaises. + +## Table des matières + +- [Vue d'ensemble](#vue-densemble) +- [Architecture monorepo](#architecture-monorepo) +- [Packages](#packages) +- [Stack technique](#stack-technique) +- [Flux de données](#flux-de-données) +- [Authentification](#authentification) +- [Base de données](#base-de-données) + +## Vue d'ensemble + +Arrhes est construit sur une architecture monorepo moderne utilisant **pnpm workspaces**. Le projet est divisé en plusieurs packages indépendants mais interconnectés, chacun ayant une responsabilité spécifique. + +``` +┌─────────────────────────────────────────────────────────┐ +│ Utilisateurs │ +└────────────────────────────┬────────────────────────────┘ + │ + ┌──────────▼──────────┐ + │ @arrhes/platform │ (Frontend React) + │ Port: 5173 │ + └──────────┬──────────┘ + │ + │ HTTP/REST + │ + ┌──────────▼──────────┐ + │ @arrhes/api │ (Backend Hono) + │ Port: 3000 │ + └──────────┬──────────┘ + │ + ┌───────────┼───────────┐ + │ │ │ + ┌────▼────┐ ┌───▼────┐ ┌───▼────┐ + │ DB │ │ S3 │ │ SMTP │ + │ (SQL) │ │ (File) │ │ (Mail) │ + └─────────┘ └────────┘ └────────┘ +``` + +## Architecture monorepo + +Le projet utilise **pnpm workspaces** pour gérer plusieurs packages dans un seul repository. Cette approche offre plusieurs avantages : + +- **Partage de code** : Les packages peuvent facilement partager du code via `@arrhes/application-metadata` +- **Dépendances optimisées** : pnpm déduplique les dépendances communes +- **Développement simplifié** : Build et développement coordonnés entre packages +- **Versioning cohérent** : Toutes les parties du projet évoluent ensemble + +### Structure du workspace + +``` +arrhes/ +├── packages/ +│ ├── api/ # Backend API +│ ├── platform/ # Interface utilisateur +│ ├── metadata/ # Schémas et types partagés +│ ├── tools/ # Outils de migration DB +│ └── website/ # Site vitrine +├── pnpm-workspace.yaml +└── package.json +``` + +## Packages + +### @arrhes/api + +**Rôle :** Backend REST API pour toutes les opérations métier + +**Technologies :** +- **Hono** : Framework web léger et performant +- **TypeScript** : Typage statique +- **Drizzle ORM** : ORM pour PostgreSQL +- **Valibot** : Validation des données +- **Nodemailer** : Envoi d'emails +- **AWS SDK** : Stockage de fichiers (S3-compatible) +- **Puppeteer** : Génération de PDF + +**Structure :** +``` +api/src/ +├── api.ts # Configuration de l'app Hono +├── server.ts # Point d'entrée du serveur +├── clients/ # Clients pour services externes +│ ├── sqlClient.ts +│ ├── emailClient.ts +│ └── storageClient.ts +├── factories/ # Factories Hono avec types +│ ├── apiFactory.ts +│ ├── authFactory.ts +│ └── publicFactory.ts +├── middlewares/ # Middlewares d'authentification +│ ├── authMiddleware.ts +│ ├── publicMiddleware.ts +│ └── userVerificationMiddleware.ts +├── routes/ # Routes de l'API +│ ├── auth/ # Routes authentifiées +│ │ ├── organizations/ # Gestion organisations +│ │ ├── settings/ # Paramètres utilisateur +│ │ └── support/ # Support +│ └── public/ # Routes publiques +│ ├── signIn.ts +│ ├── signUp.ts +│ ├── signOut.ts +│ └── sendMagicLink.ts +└── utilities/ # Utilitaires + ├── email/ # Templates et envoi emails + ├── sql/ # Helpers SQL + ├── storage/ # Helpers S3 + ├── cookies/ # Gestion cookies sécurisés + └── workspace/ # Logique métier +``` + +**Points d'entrée :** +- `server.ts` : Lance le serveur HTTP +- `api.ts` : Configure l'application Hono avec middlewares et routes + +**Responsabilités :** +- Gestion de l'authentification (magic links, sessions) +- CRUD pour toutes les entités (organisations, comptes, écritures, etc.) +- Validation des écritures comptables +- Génération des états financiers +- Gestion des pièces justificatives (upload/download via S3) +- Envoi d'emails transactionnels + +### @arrhes/platform + +**Rôle :** Interface utilisateur web pour interagir avec l'application + +**Technologies :** +- **React 19** : Framework UI +- **TanStack Router** : Routing type-safe +- **TanStack Query** : Gestion d'état serveur et cache +- **TanStack Table** : Tableaux de données performants +- **TanStack Virtual** : Virtualisation pour grandes listes +- **Radix UI** : Composants accessibles headless +- **Panda CSS** : Framework CSS utility-first +- **React Hook Form** : Gestion de formulaires +- **Valibot** : Validation côté client +- **Vite** : Build tool et dev server + +**Structure :** +``` +platform/src/ +├── root.tsx # Point d'entrée React +├── index.html # HTML principal +├── assets/ # Ressources statiques +│ ├── css/ +│ ├── fonts/ +│ ├── images/ +│ └── manifest/ # PWA manifest +├── components/ # Composants réutilisables +│ ├── buttons/ +│ ├── formats/ # Formatage de données +│ ├── forms/ +│ ├── inputs/ +│ ├── layouts/ +│ └── overlays/ # Modals, dropdowns, tooltips +├── contexts/ # Contexts React +│ ├── data/ # Context de données globales +│ ├── router/ # Configuration du router +│ └── toasts/ # Notifications +├── features/ # Features par domaine métier +│ ├── authLayout.tsx +│ ├── organizations/ # Gestion organisations +│ ├── settings/ +│ ├── signIn/ +│ ├── signUp/ +│ └── support/ +├── routes/ # Définition des routes +│ ├── platformRouter.tsx +│ ├── platformTree.ts +│ └── root/ # Routes de l'app +└── utilities/ # Utilitaires + ├── postAPI.ts # Client API + ├── useHTTPData.ts # Hook pour data fetching + └── cookies/ # Gestion cookies +``` + +**Responsabilités :** +- Interface utilisateur complète +- Formulaires de saisie avec validation +- Tableaux de données avec tri, filtrage, pagination +- Visualisation des états financiers +- Gestion des documents et pièces justificatives +- Notifications et retours utilisateur + +### @arrhes/application-metadata + +**Rôle :** Package partagé contenant tous les schémas, modèles et types utilisés par l'API et la plateforme + +**Technologies :** +- **Drizzle ORM** : Définition des schémas de base de données +- **Valibot** : Schémas de validation +- **TypeScript** : Types partagés + +**Structure :** +``` +metadata/src/ +├── models/ # Modèles Drizzle ORM +│ ├── user.ts +│ ├── organization.ts +│ ├── account.ts +│ ├── journal.ts +│ ├── record.ts # Écritures comptables +│ ├── recordRow.ts # Lignes d'écriture +│ ├── document.ts +│ ├── attachment.ts +│ ├── year.ts +│ ├── balanceSheet.ts +│ ├── incomeStatement.ts +│ └── computation.ts +├── schemas/ # Schémas Valibot pour validation +│ └── [mêmes fichiers que models/] +├── routes/ # Définitions de routes typées +│ ├── auth/ +│ └── public/ +├── components/ # Composants métier partagés +│ ├── models/ +│ ├── schemas/ +│ └── values/ # Valeurs par défaut et constantes +└── utilities/ # Utilitaires + ├── generate.ts + ├── generateId.ts + └── routeDefinition.ts +``` + +**Exports :** +```typescript +// Utilisable par l'API et la plateforme +import { models } from '@arrhes/application-metadata/models' +import { schemas } from '@arrhes/application-metadata/schemas' +import { routes } from '@arrhes/application-metadata/routes' +import { generateId } from '@arrhes/application-metadata/utilities' +``` + +**Responsabilités :** +- Définition unique des schémas de base de données +- Validation cohérente des données entre frontend et backend +- Types TypeScript partagés +- Génération d'IDs uniques (nanoid) +- Définitions de routes type-safe + +### @arrhes/tools + +**Rôle :** Outils de gestion de la base de données (migrations, seed, maintenance) + +**Technologies :** +- **Drizzle Kit** : CLI pour migrations +- **tsx** : Exécution TypeScript +- **Postgres** : Client PostgreSQL + +**Scripts disponibles :** +```bash +# Générer les migrations depuis le schéma +pnpm --filter tools run generate + +# Pousser le schéma directement vers la DB +pnpm --filter tools run push + +# Appliquer les migrations +pnpm --filter tools run migrate + +# Seed avec données de démonstration +pnpm --filter tools run seed + +# Vider la base de données +pnpm --filter tools run clear + +# Reset complet (clear + push + seed) +pnpm --filter tools run reset + +# Supprimer les migrations +pnpm --filter tools run drop +``` + +**Structure :** +``` +tools/src/ +├── env.ts # Configuration environnement +├── schemas.ts # Import des schémas metadata +├── migrate.ts # Script de migration +├── clearDB.ts # Script de nettoyage +└── seed/ # Scripts de seed + ├── seed.ts # Seed principal + ├── migration.ts # Migrations de données + ├── records2022.ts # Données exemple 2022 + └── records2023.ts # Données exemple 2023 +``` + +**Responsabilités :** +- Gestion du schéma de base de données +- Migrations de structure et de données +- Génération de données de test +- Maintenance de la base de données + +### @arrhes/website + +**Rôle :** Site vitrine pour présenter l'application + +**Technologies :** +- **React** : Framework UI +- **Vite** : Build tool + +**Note :** Package actuellement minimal, prévu pour évoluer en site marketing/landing page. + +## Stack technique + +### Backend (API) + +| Composant | Technologie | Rôle | +|-----------|-------------|------| +| Runtime | Node.js 24.5+ | Environnement d'exécution | +| Language | TypeScript 5.9 | Langage de programmation | +| Framework | Hono 4.9 | Framework web minimaliste | +| ORM | Drizzle 0.44 | Mapping objet-relationnel | +| Validation | Valibot 1.1 | Validation de schémas | +| Database | PostgreSQL | Base de données relationnelle | +| Storage | AWS S3 SDK | Stockage de fichiers | +| Email | Nodemailer 7.0 | Envoi d'emails | +| PDF | Puppeteer 24.22 | Génération de PDF | + +### Frontend (Platform) + +| Composant | Technologie | Rôle | +|-----------|-------------|------| +| Framework | React 19.1 | UI framework | +| Routing | TanStack Router 1.132 | Routing type-safe | +| State | TanStack Query 5.90 | Server state management | +| Tables | TanStack Table 8.21 | Data tables | +| Virtual | TanStack Virtual 3.13 | Virtualisation listes | +| UI | Radix UI | Composants accessibles | +| Styling | Panda CSS | CSS utility-first | +| Forms | React Hook Form 7.63 | Gestion de formulaires | +| Validation | Valibot 1.1 | Validation client-side | +| Icons | Tabler Icons 3.35 | Icônes | +| Build | Vite 7.1 | Build tool moderne | + +### Tooling + +| Outil | Version | Rôle | +|-------|---------|------| +| pnpm | Latest | Package manager | +| TypeScript | 5.9 | Compilateur TypeScript | +| ESLint | 9.36 | Linter JavaScript/TypeScript | +| Drizzle Kit | 0.31 | Migrations de base de données | +| tsx | 4.20 | Exécution TypeScript | + +## Flux de données + +### Authentification par Magic Link + +``` +1. Utilisateur entre son email + └─> POST /api/public/sendMagicLink + └─> Génération token + envoi email + +2. Utilisateur clique sur le lien + └─> GET /api/public/signIn?token=xxx + └─> Validation token + └─> Création session + └─> Cookie sécurisé (httpOnly, signed) + └─> Redirection vers plateforme + +3. Requêtes authentifiées + └─> Cookie envoyé automatiquement + └─> authMiddleware vérifie session + └─> Accès aux routes protégées +``` + +### CRUD standard + +``` +Platform API Database +──────────────────────────────────────────────────────────── +1. User action + └─> postAPI() + └─> POST /api/auth/... + └─> authMiddleware + └─> Validation données (Valibot) + └─> Drizzle ORM + └─> SQL Query + └─> PostgreSQL + +2. Response + ┌─ JSON + └─ TanStack Query cache + └─ Invalidation automatique + └─ Re-fetch et mise à jour UI +``` + +### Upload de fichiers + +``` +1. Sélection fichier + └─> Demande URL signée PUT + └─> POST /api/auth/.../generatePutSignedUrl + └─> S3 génère URL temporaire (expires 15min) + +2. Upload direct vers S3 + └─> PUT https://s3.../file + (pas de passage par l'API) + +3. Sauvegarde référence + └─> POST /api/auth/.../attachment + └─> Stocke storageKey en DB +``` + +### Download de fichiers + +``` +1. Demande URL signée GET + └─> POST /api/auth/.../generateGetSignedUrl + └─> S3 génère URL temporaire (expires 1h) + +2. Download direct depuis S3 + └─> GET https://s3.../file + (pas de passage par l'API) +``` + +## Authentification + +### Stratégie + +Arrhes utilise une **authentification par magic link** (lien temporaire envoyé par email) combinée à des **sessions persistantes** côté serveur. + +### Flow complet + +1. **Inscription** (`/api/public/signUp`) + - Validation email + alias + - Hash du mot de passe (PBKDF2, 128000 itérations) + - Création user + - Envoi email de vérification + +2. **Connexion** (`/api/public/sendMagicLink`) + - Génération token de vérification unique + - Stockage temporaire en DB + - Envoi email avec lien + +3. **Validation** (`/api/public/signIn`) + - Vérification du token + - Création d'une session + - Cookie signé et httpOnly + - Redirection vers l'application + +4. **Requêtes authentifiées** + - Cookie envoyé automatiquement + - `authMiddleware` vérifie la session + - Charge l'utilisateur en contexte + - Vérifie l'appartenance à l'organisation si nécessaire + +5. **Déconnexion** (`/api/public/signOut`) + - Suppression de la session en DB + - Suppression du cookie + +### Sécurité + +- **Cookies signés** : Vérification de l'intégrité avec `COOKIES_KEY` +- **httpOnly** : Protection contre XSS +- **sameSite** : Protection contre CSRF +- **CORS configuré** : Origine autorisée uniquement +- **Tokens temporaires** : Expiration des magic links +- **Hashing sécurisé** : PBKDF2 avec salt unique par utilisateur + +## Base de données + +### Schéma principal + +Le schéma PostgreSQL contient les tables suivantes (via Drizzle ORM) : + +**Utilisateurs et organisations :** +- `user` : Utilisateurs de l'application +- `organization` : Organisations (entreprises/associations) +- `organizationUser` : Relation many-to-many avec rôles +- `userSession` : Sessions actives + +**Comptabilité :** +- `year` : Exercices comptables +- `account` : Plan comptable +- `journal` : Journaux comptables +- `record` : Écritures comptables +- `recordRow` : Lignes d'écriture (débit/crédit) +- `document` : Documents comptables +- `attachment` : Pièces justificatives + +**États financiers :** +- `balanceSheet` : Configuration du bilan +- `incomeStatement` : Configuration du compte de résultat +- `computation` : Calculs personnalisés +- `computationIncomeStatement` : Relation calculs/compte de résultat + +### Relations clés + +``` +organization 1──n organizationUser n──1 user + │ + ├── 1──n year + ├── 1──n account + ├── 1──n journal + └── 1──n document + │ + └── 1──n record + │ + └── 1──n recordRow + │ + └── n──1 account +``` + +### Migrations + +Les migrations sont gérées par **Drizzle Kit** : +- Le schéma source est défini dans `@arrhes/application-metadata` +- Drizzle Kit génère automatiquement les migrations SQL +- Application via `drizzle-kit migrate` ou `push` (dev) + +## Diagramme de dépendances + +``` +@arrhes/platform ──depends on──> @arrhes/application-metadata + ▲ + │ +@arrhes/api ──depends on───────────┘ + ▲ + │ +@arrhes/tools ──depends on───────────┘ + +@arrhes/website (indépendant) +``` + +Tous les packages dépendent de `@arrhes/application-metadata` pour partager les schémas, modèles et types. Cette architecture assure une cohérence totale entre le frontend et le backend. + +--- + +Pour plus d'informations sur la configuration, consultez [CONFIGURATION.md](CONFIGURATION.md). diff --git a/docs/BUSINESS_MODEL.md b/docs/BUSINESS_MODEL.md new file mode 100644 index 0000000..ddc30df --- /dev/null +++ b/docs/BUSINESS_MODEL.md @@ -0,0 +1,101 @@ +# Business Model Strategy + +This document outlines the business model strategy for Arrhes, an open-source double-entry accounting application for French associations and SMEs. + +## Goals + +- Maximum adoption among indie hackers, solofounders, and community growth +- Sustainable revenue from businesses (and accountants later) +- AI agent as core differentiator + +## Model: Open-Core SaaS with Community Focus + +### Tier Structure + +| Tier | Price | Target | Features | +|------|-------|--------|----------| +| **Self-hosted** | Free forever | Developers, tech-savvy users | Full core app, deploy yourself | +| **Cloud Free** | 0 EUR/month | Micro-associations, testing | 1 org, 1 user, 100 ecritures/month, no agent | +| **Cloud Pro** | 9-15 EUR/month | Associations, solopreneurs | Unlimited ecritures, 3 users, basic agent features | +| **Cloud Business** | 29-49 EUR/month | SMEs, accountants | Unlimited users, full AI agent, priority support, API access | + +### Free Features (Open-Source Core) + +- Full double-entry accounting +- All journals, accounts, records +- Balance sheet & income statement +- Document/attachment management +- Multi-organization support +- Self-hosting with Docker + +### Paid Features (Premium/Agent) + +**AI Agent (core differentiator):** +- Auto-categorization of transactions +- Anomaly detection +- Natural language queries +- Automated reconciliation suggestions +- FEC generation assistance + +**Cloud conveniences:** +- Automatic backups +- SSL/security managed +- No maintenance burden + +**Business features:** +- Advanced exports (FEC, Excel, custom PDF reports) +- Bank synchronization (future) +- Multi-user with granular permissions +- API access for integrations + +## Community Growth Strategy + +1. **Make self-hosting simple** + - One-click deploy buttons (Railway, Render, Coolify, Dokploy) + - Docker Compose setup + - Clear documentation + +2. **Developer-first marketing** + - Hacker News, Reddit (r/selfhosted, r/SideProject, r/France) + - Indie Hackers community + - Product Hunt launch + - French tech communities + +3. **Open development** + - Public roadmap (GitHub Projects) + - Transparent changelog + - Accept contributions + +4. **Content marketing** + - Blog posts on French accounting + - Self-hosting tutorials + - Comparison guides + +## Revenue Streams + +| Stream | Priority | Notes | +|--------|----------|-------| +| Cloud subscriptions | Primary | Recurring, predictable | +| AI agent add-on | High | Differentiator, high perceived value | +| Annual plans | Medium | Cash flow + retention | +| Accountant partnerships | Later | Volume deals, requires sales effort | + +**Initial target:** 100 paying customers at 15 EUR/mo avg = 1,500 EUR/mo MRR + +## Competitive Positioning + +| Competitor | Their Position | Arrhes Advantage | +|------------|----------------|------------------| +| Dolibarr | ERP, complex, old UI | Modern UX, accounting-focused | +| OpenConcerto | Desktop-first | Cloud-native, modern stack | +| Pennylane | VC-funded, expensive | Open-source, self-hostable, affordable | +| Tiime | Free but limited | More control, no lock-in | + +**Positioning statement:** *"The open-source accounting tool for French associations and small businesses, with an AI assistant that actually understands your books."* + +## Open Questions + +- **Pricing model:** Per-organization vs per-user vs usage-based? +- **Agent positioning:** Separate add-on or bundled into higher tiers? +- **Free tier limits:** Balance between adoption and conversion +- **Launch timing:** Core product first, or wait for agent to differentiate? diff --git a/docs/CONFIGURATION.md b/docs/CONFIGURATION.md new file mode 100644 index 0000000..5a92889 --- /dev/null +++ b/docs/CONFIGURATION.md @@ -0,0 +1,480 @@ +# Configuration + +Ce document décrit toutes les variables d'environnement et les configurations nécessaires pour faire fonctionner Arrhes en développement local. + +## Table des matières + +- [Vue d'ensemble](#vue-densemble) +- [Variables d'environnement - API](#variables-denvironnement---api) +- [Variables d'environnement - Tools](#variables-denvironnement---tools) +- [Configuration PostgreSQL](#configuration-postgresql) +- [Configuration S3 (Stockage)](#configuration-s3-stockage) +- [Configuration SMTP (Email)](#configuration-smtp-email) +- [Exemples de configuration](#exemples-de-configuration) +- [Sécurité](#sécurité) + +## Vue d'ensemble + +Arrhes nécessite deux fichiers de configuration `.env` : + +1. **`packages/api/.env`** : Configuration du backend API +2. **`packages/tools/.env`** : Configuration des outils de base de données + +Ces fichiers ne sont **pas versionnés** (`.gitignore`) pour des raisons de sécurité. + +### Approches de configuration + +**Option 1 : Avec Docker Compose (Recommandé) 🐳** + +Le fichier `docker-compose.yml` à la racine du projet lance automatiquement PostgreSQL, RustFS et MailHog avec des valeurs par défaut prêtes à l'emploi. Cette option simplifie la configuration. + +**Option 2 : Installation native** + +Vous installez et configurez manuellement chaque service sur votre machine. + +Ce document couvre les deux approches. + +## Variables d'environnement - API + +Fichier : `packages/api/.env` + +### Environnement général + +| Variable | Type | Description | Exemple | +|----------|------|-------------|---------| +| `ENV` | `"development"` \| `"production"` | Environnement d'exécution | `development` | +| `VERBOSE` | `"true"` \| `"false"` | Mode verbeux (logs détaillés) | `true` | +| `PORT` | `string` | Port d'écoute du serveur | `3000` | + +### CORS et Cookies + +| Variable | Type | Description | Exemple | +|----------|------|-------------|---------| +| `CORS_ORIGIN` | `string` | Origines autorisées (séparées par virgule) | `http://localhost:5173` | +| `COOKIES_DOMAIN` | `string` | Domaine des cookies | `localhost` | +| `COOKIES_KEY` | `string` | Clé secrète pour signer les cookies (min 32 chars) | `your-super-secret-key-min-32-characters-long` | + +### URLs des services + +| Variable | Type | Description | Exemple | +|----------|------|-------------|---------| +| `API_BASE_URL` | `string` | URL de base de l'API | `http://localhost:3000` | +| `PLATFORM_BASE_URL` | `string` | URL de la plateforme frontend | `http://localhost:5173` | +| `WEBSITE_BASE_URL` | `string` | URL du site vitrine | `http://localhost:5174` | + +### Base de données + +| Variable | Type | Description | Exemple | +|----------|------|-------------|---------| +| `SQL_DATABASE_URL` | `string` | URL de connexion PostgreSQL | `postgres://user:password@localhost:5432/arrhes` | + +### Stockage S3 + +| Variable | Type | Description | Exemple | +|----------|------|-------------|---------| +| `STORAGE_ENDPOINT` | `string` | Endpoint S3 (ou compatible) | `http://localhost:9000` (RustFS) | +| `STORAGE_BUCKET_NAME` | `string` | Nom du bucket S3 | `arrhes-files` | +| `STORAGE_ACCESS_KEY` | `string` | Clé d'accès S3 | `arrhes_rustfs` | +| `STORAGE_SECRET_KEY` | `string` | Clé secrète S3 | `arrhes_rustfs_secret` | + +### Email SMTP + +| Variable | Type | Description | Exemple | +|----------|------|-------------|---------| +| `EMAIL_ENDPOINT` | `string` | Serveur SMTP | `smtp.gmail.com` | +| `EMAIL_USER` | `string` | Utilisateur SMTP | `your-email@gmail.com` | +| `EMAIL_PASSWORD` | `string` | Mot de passe ou app password SMTP | `your-app-password` | + +## Variables d'environnement - Tools + +Fichier : `packages/tools/.env` + +| Variable | Type | Description | Exemple | +|----------|------|-------------|---------| +| `DATABASE_URL` | `string` | URL de connexion PostgreSQL | `postgres://user:password@localhost:5432/arrhes` | + +**Note :** Cette variable doit être identique à `SQL_DATABASE_URL` de l'API. + +## Configuration PostgreSQL + +### Option 1 : Avec Docker Compose (Recommandé) 🐳 + +Aucune installation manuelle requise ! Le fichier `docker-compose.yml` configure automatiquement PostgreSQL. + +**Lancer PostgreSQL :** +```bash +docker-compose up -d postgres +``` + +**Configuration par défaut :** +- **Host** : `localhost` +- **Port** : `5432` +- **Database** : `arrhes` +- **User** : `arrhes_user` +- **Password** : `arrhes_password` +- **URL** : `postgres://arrhes_user:arrhes_password@localhost:5432/arrhes` + +**Vérification de la connexion :** +```bash +psql postgres://arrhes_user:arrhes_password@localhost:5432/arrhes +``` + +**Commandes utiles :** +```bash +# Voir les logs +docker-compose logs postgres + +# Redémarrer +docker-compose restart postgres + +# Arrêter +docker-compose stop postgres +``` + +### Option 2 : Installation native + +**Ubuntu/Debian :** +```bash +sudo apt update +sudo apt install postgresql postgresql-contrib +sudo systemctl start postgresql +``` + +**macOS (Homebrew) :** +```bash +brew install postgresql@16 +brew services start postgresql@16 +``` + +**Windows :** +Télécharger l'installeur depuis [postgresql.org](https://www.postgresql.org/download/windows/) + +**Création de la base de données :** +```bash +# Se connecter à PostgreSQL +sudo -u postgres psql + +# Créer un utilisateur +CREATE USER arrhes_user WITH PASSWORD 'your-secure-password'; + +# Créer la base de données +CREATE DATABASE arrhes OWNER arrhes_user; + +# Donner tous les privilèges +GRANT ALL PRIVILEGES ON DATABASE arrhes TO arrhes_user; + +# Quitter +\q +``` + +**URL de connexion :** + +Format : `postgres://[user]:[password]@[host]:[port]/[database]` + +Exemple : `postgres://arrhes_user:your-secure-password@localhost:5432/arrhes` + +**Vérification de la connexion :** +```bash +psql postgres://arrhes_user:your-secure-password@localhost:5432/arrhes +``` + +## Configuration S3 (Stockage) + +Le système de stockage utilise l'API AWS S3 mais fonctionne avec n'importe quel service compatible S3. + +### Option 1 : Avec Docker Compose (Recommandé) 🐳 + +Le fichier `docker-compose.yml` lance automatiquement RustFS. + +**Lancer RustFS :** +```bash +docker-compose up -d rustfs +``` + +**Configuration par défaut :** +- **Endpoint** : `http://localhost:9000` +- **Web UI** : http://localhost:9001 +- **Access Key** : `arrhes_rustfs` +- **Secret Key** : `arrhes_rustfs_secret` +- **Bucket** : `arrhes-files` (à créer) + +**Variables d'environnement :** +```env +STORAGE_ENDPOINT=http://localhost:9000 +STORAGE_BUCKET_NAME=arrhes-files +STORAGE_ACCESS_KEY=arrhes_rustfs +STORAGE_SECRET_KEY=arrhes_rustfs_secret +``` + +**Création du bucket :** + +Via l'interface web : +1. Accéder à http://localhost:9001 +2. Se connecter avec `arrhes_rustfs` / `arrhes_rustfs_secret` +3. Cliquer sur "Buckets" > "Create Bucket" +4. Nommer le bucket `arrhes-files` + +**Commandes utiles :** +```bash +# Voir les logs +docker-compose logs rustfs + +# Redémarrer +docker-compose restart rustfs +``` + +### Option 2 : MinIO standalone (sans Docker Compose) + +**Installation avec Docker :** +```bash +docker run -d \ + -p 9000:9000 \ + -p 9001:9001 \ + --name rustfs \ + + -e "RUSTFS_ROOT_USER=arrhes_rustfs" \ + -e "RUSTFS_ROOT_PASSWORD=arrhes_rustfs_secret" \ + -v ~/rustfs/data:/data \ + rustfs/rustfs:latest server /data --web-ui-address ":9001" +``` + +Suivez ensuite les mêmes étapes de création de bucket que ci-dessus. + +### Option 3 : AWS S3 (Production) + +**Configuration :** +```env +STORAGE_ENDPOINT=https://s3.eu-west-3.amazonaws.com +STORAGE_BUCKET_NAME=your-bucket-name +STORAGE_ACCESS_KEY=YOUR_AWS_ACCESS_KEY +STORAGE_SECRET_KEY=YOUR_AWS_SECRET_KEY +``` + +**Prérequis :** +- Créer un bucket S3 dans votre région +- Créer un utilisateur IAM avec les permissions S3 appropriées +- Générer des clés d'accès pour cet utilisateur + +### Option 3 : Autre service compatible S3 + +Cloudflare R2, DigitalOcean Spaces, Scaleway Object Storage, etc. sont également compatibles. + +## Configuration SMTP (Email) + +L'application envoie des emails pour : +- Magic links d'authentification +- Notifications importantes +- Invitations d'utilisateurs + +### Option 1 : Avec Docker Compose (Recommandé pour le développement) 🐳 + +Le fichier `docker-compose.yml` lance automatiquement MailHog, un serveur SMTP de test. + +**Lancer MailHog :** +```bash +docker-compose up -d mailhog +``` + +**Configuration par défaut :** +- **SMTP** : `localhost:1025` +- **Interface web** : http://localhost:8025 + +**Variables d'environnement :** +```env +EMAIL_ENDPOINT=localhost:1025 +EMAIL_USER=test +EMAIL_PASSWORD=test +``` + +**Interface web :** +Accédez à http://localhost:8025 pour voir tous les emails envoyés par l'application. + +**Avantages :** +- Aucun email réel n'est envoyé +- Visualisation de tous les emails +- Idéal pour le développement et les tests + +**Commandes utiles :** +```bash +# Voir les logs +docker-compose logs mailhog + +# Redémarrer +docker-compose restart mailhog +``` + +### Option 2 : MailHog standalone (sans Docker Compose) + +```bash +docker run -d -p 1025:1025 -p 8025:8025 mailhog/mailhog +``` + +Utilisez la même configuration que ci-dessus. + +### Option 3 : Gmail (Test avec vrais emails) + +**Configuration :** +```env +EMAIL_ENDPOINT=smtp.gmail.com +EMAIL_USER=your-email@gmail.com +EMAIL_PASSWORD=your-app-specific-password +``` + +**Étapes :** +1. Activer l'authentification à deux facteurs sur votre compte Google +2. Générer un "mot de passe d'application" : https://myaccount.google.com/apppasswords +3. Utiliser ce mot de passe dans `EMAIL_PASSWORD` + +### Option 4 : Services SMTP dédiés (Production) + +**Brevo (ex-Sendinblue) :** +```env +EMAIL_ENDPOINT=smtp-relay.brevo.com +EMAIL_USER=your-email@example.com +EMAIL_PASSWORD=your-smtp-key +``` + +**SendGrid :** +```env +EMAIL_ENDPOINT=smtp.sendgrid.net +EMAIL_USER=apikey +EMAIL_PASSWORD=your-sendgrid-api-key +``` + +**Mailgun :** +```env +EMAIL_ENDPOINT=smtp.mailgun.org +EMAIL_USER=postmaster@your-domain.mailgun.org +EMAIL_PASSWORD=your-smtp-password +``` + +## Exemples de configuration + +### Configuration avec Docker Compose 🐳 (Recommandé) + +Cette configuration utilise tous les services lancés par `docker-compose.yml`. + +**Étape 1 : Lancer les services** +```bash +docker-compose up -d +``` + +**Étape 2 : `packages/api/.env`** +```env +# Environnement +ENV=development +VERBOSE=true +PORT=3000 + +# CORS et Cookies +CORS_ORIGIN=http://localhost:5173 +COOKIES_DOMAIN=localhost +COOKIES_KEY=development-secret-key-change-in-production-min-32-chars + +# URLs +API_BASE_URL=http://localhost:3000 +PLATFORM_BASE_URL=http://localhost:5173 +WEBSITE_BASE_URL=http://localhost:5174 + +# Base de données (Docker Compose) +SQL_DATABASE_URL=postgres://arrhes_user:arrhes_password@localhost:5432/arrhes + +# Stockage MinIO (Docker Compose) +STORAGE_ENDPOINT=http://localhost:9000 +STORAGE_BUCKET_NAME=arrhes-files +STORAGE_ACCESS_KEY=arrhes_rustfs +STORAGE_SECRET_KEY=arrhes_rustfs_secret + + +# Email (MailHog Docker standalone) +EMAIL_ENDPOINT=localhost:1025 +EMAIL_USER=test +EMAIL_PASSWORD=test +``` + +**`packages/tools/.env` :** +```env +DATABASE_URL=postgres://arrhes_user:your-password@localhost:5432/arrhes +``` + +### Configuration avec services externes (Production) + +**`packages/api/.env` :** +```env +# Environnement +ENV=development +VERBOSE=true +PORT=3000 + +# CORS et Cookies +CORS_ORIGIN=http://localhost:5173 +COOKIES_DOMAIN=localhost +COOKIES_KEY=generate-a-strong-random-key-here-minimum-32-characters + +# URLs +API_BASE_URL=http://localhost:3000 +PLATFORM_BASE_URL=http://localhost:5173 +WEBSITE_BASE_URL=http://localhost:5174 + +# Base de données (PostgreSQL hébergé) +SQL_DATABASE_URL=postgres://user:pass@db.provider.com:5432/arrhes + +# Stockage AWS S3 +STORAGE_ENDPOINT=https://s3.eu-west-3.amazonaws.com +STORAGE_BUCKET_NAME=my-arrhes-bucket +STORAGE_ACCESS_KEY=AKIAIOSFODNN7EXAMPLE +STORAGE_SECRET_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY + +# Email (Gmail) +EMAIL_ENDPOINT=smtp.gmail.com +EMAIL_USER=myemail@gmail.com +EMAIL_PASSWORD=abcd efgh ijkl mnop +``` + +## Sécurité + +### Bonnes pratiques + +1. **Ne jamais commiter les fichiers `.env`** + - Vérifiez que `.env` est dans `.gitignore` + - Utilisez des templates `.env.example` sans valeurs sensibles + +2. **Générer des secrets forts** + ```bash + # Générer une clé aléatoire pour COOKIES_KEY + openssl rand -base64 32 + ``` + +3. **Permissions de fichiers** + ```bash + # Restreindre l'accès aux fichiers .env + chmod 600 packages/api/.env + chmod 600 packages/tools/.env + ``` + +4. **Variables séparées par environnement** + - Dev : `.env.development` + - Production : `.env.production` + - Ne jamais mélanger les credentials + +5. **Rotation des secrets** + - Changez régulièrement `COOKIES_KEY` + - Renouvelez les clés API et mots de passe + - Révoquez les accès inutilisés + +### Vérification de la configuration + +Pour vérifier que toutes les variables sont correctement définies, l'API affichera une erreur au démarrage si des variables sont manquantes ou invalides (validation via Valibot dans `getEnv.ts`). + +### Valeurs recommandées + +| Variable | Recommandation | +|----------|----------------| +| `COOKIES_KEY` | Minimum 32 caractères aléatoires | +| `SQL_DATABASE_URL` | Connexion SSL en production (`?sslmode=require`) | +| `STORAGE_*` | Credentials avec permissions minimales (lecture/écriture bucket uniquement) | +| `EMAIL_*` | Utiliser des app passwords, pas le mot de passe principal | + +--- + +Pour poursuivre l'installation, consultez [DEVELOPMENT.md](DEVELOPMENT.md). diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md new file mode 100644 index 0000000..3dc64a5 --- /dev/null +++ b/docs/CONTRIBUTING.md @@ -0,0 +1,551 @@ +# Guide de contribution + +Merci de votre intérêt pour contribuer à Arrhes ! Ce document explique comment participer au développement du projet. + +## Table des matières + +- [Code de conduite](#code-de-conduite) +- [Comment contribuer](#comment-contribuer) +- [Configuration de l'environnement](#configuration-de-lenvironnement) +- [Standards de code](#standards-de-code) +- [Convention de commits](#convention-de-commits) +- [Process de pull request](#process-de-pull-request) +- [Tests](#tests) +- [Code review](#code-review) +- [Signaler un bug](#signaler-un-bug) +- [Proposer une fonctionnalité](#proposer-une-fonctionnalité) + +## Code de conduite + +En participant à ce projet, vous vous engagez à maintenir un environnement respectueux et inclusif. Nous attendons de tous les contributeurs : + +- Respect et courtoisie envers les autres contributeurs +- Ouverture d'esprit face aux critiques constructives +- Concentration sur ce qui est le mieux pour la communauté +- Empathie envers les autres membres de la communauté + +Les comportements inacceptables incluent le harcèlement, les insultes, et tout comportement discriminatoire. + +## Comment contribuer + +Il existe plusieurs façons de contribuer à Arrhes : + +### 🐛 Signaler des bugs +Ouvrez une issue sur GitHub avec le label `bug` + +### 💡 Proposer des fonctionnalités +Ouvrez une issue sur GitHub avec le label `enhancement` + +### 📝 Améliorer la documentation +La documentation est aussi importante que le code ! + +### 💻 Contribuer du code +Suivez le process décrit dans ce document + +### 🌍 Traductions +Aidez à traduire l'application dans d'autres langues + +### 🎨 Design et UX +Proposez des améliorations d'interface + +## Configuration de l'environnement + +Avant de commencer à contribuer, configurez votre environnement de développement : + +1. **Fork le repository** sur votre compte GitHub + +2. **Cloner votre fork** + ```bash + git clone https://github.com/votre-username/arrhes.git + cd arrhes + ``` + +3. **Ajouter le repository principal comme remote** + ```bash + git remote add upstream https://github.com/arrhes/arrhes-application.git + ``` + +4. **Choisir votre méthode de développement** + + **Option A : Dev Container (Recommandé pour les nouveaux contributeurs) 🚀** + + C'est la méthode la plus simple pour démarrer rapidement : + + ```bash + # Ouvrir dans VS Code/Cursor + code . # ou cursor . + + # Cliquer sur "Reopen in Container" quand demandé + # Tout sera configuré automatiquement ! + ``` + + **Option B : Docker Compose** + + ```bash + # Installer les dépendances + pnpm install + + # Lancer les services + docker-compose up -d + + # Configurer l'environnement + # Suivez les instructions dans DEVELOPMENT.md + ``` + + **Option C : Installation native** + + ```bash + # Installer les dépendances + pnpm install + + # Configurer l'environnement + # Suivez les instructions complètes dans DEVELOPMENT.md + ``` + +5. **Créer une branche pour votre contribution** + ```bash + git checkout -b feature/ma-fonctionnalite + # ou + git checkout -b fix/mon-correctif + ``` + +Pour plus de détails, consultez [DEVELOPMENT.md](DEVELOPMENT.md). + +## Standards de code + +### TypeScript + +- **Utiliser TypeScript strict** : Pas de `any`, sauf exception justifiée +- **Typage explicite** pour les fonctions publiques +- **Interfaces vs Types** : Préférer `type` pour les objets simples, `interface` pour l'extension + +**Bon exemple :** +```typescript +type User = { + id: string + email: string + alias: string +} + +function createUser(data: { email: string, alias: string }): User { + return { + id: generateId(), + ...data, + } +} +``` + +**Mauvais exemple :** +```typescript +function createUser(data: any) { // ❌ any + return { + id: generateId(), + ...data, + } +} +``` + +### Naming conventions + +- **Variables et fonctions** : `camelCase` +- **Types et interfaces** : `PascalCase` +- **Constantes** : `UPPER_SNAKE_CASE` (si vraiment constante) +- **Fichiers** : `camelCase.ts` +- **Composants React** : `PascalCase.tsx` + +```typescript +// Variables et fonctions +const userName = 'John' +function getUserById(id: string) { } + +// Types +type UserProfile = { } +interface ApiResponse { } + +// Constantes +const MAX_RETRY_COUNT = 3 + +// Fichiers +// api/routes/auth/userProfile.ts +// platform/components/buttons/PrimaryButton.tsx +``` + +### Structure du code + +**Ordre des imports :** +```typescript +// 1. Imports de packages externes +import { Hono } from 'hono' +import * as v from 'valibot' + +// 2. Imports de workspace packages +import { models } from '@arrhes/application-metadata/models' +import { schemas } from '@arrhes/application-metadata/schemas' + +// 3. Imports relatifs du package actuel +import { authFactory } from '#/factories/authFactory.js' +import { validate } from '#/utilities/validate.js' +``` + +**Ordre dans les fichiers :** +```typescript +// 1. Imports +import { ... } from '...' + +// 2. Types et interfaces +type MyType = { } + +// 3. Constantes +const MY_CONSTANT = 'value' + +// 4. Fonctions/composants +export function myFunction() { } + +// 5. Export par défaut (si applicable) +export default MyComponent +``` + +### ESLint + +Le projet utilise ESLint pour maintenir la qualité du code. + +**Vérifier le linting :** +```bash +pnpm --filter platform run lint +``` + +**Fix automatique :** +```bash +pnpm --filter platform run lint --fix +``` + +**Configuration :** +- ESLint est configuré pour TypeScript et React +- Les règles sont définies dans `packages/platform/eslint.config.js` + +### Formatage + +**Indentation :** 4 espaces (pas de tabs) + +**Longueur de ligne :** Pas de limite stricte, mais restez raisonnable (~120 caractères) + +**Points-virgules :** Non requis (sauf cas spécifiques) + +**Quotes :** Simples `'` ou doubles `"` (soyez cohérent dans un fichier) + +**Trailing commas :** Oui pour les objets et arrays multilignes + +```typescript +const user = { + id: '123', + name: 'John', + email: 'john@example.com', // trailing comma +} +``` + +### React + +**Composants fonctionnels uniquement** +```typescript +export function MyComponent() { + return
Hello
+} +``` + +**Hooks en début de composant** +```typescript +export function MyComponent() { + // Hooks en premier + const [state, setState] = useState() + const query = useQuery() + + // Puis logique + const handleClick = () => { } + + // Puis render + return
...
+} +``` + +**Props destructurées** +```typescript +export function MyComponent({ title, description, onClose }: MyComponentProps) { + return
{title}
+} +``` + +**Éviter les inline styles** (utiliser Panda CSS) +```typescript +// ✅ Bon +
+ +// ❌ Éviter +
+``` + +## Convention de commits + +Nous utilisons une convention de commits inspirée de [Conventional Commits](https://www.conventionalcommits.org/). + +### Format + +``` +(): + +[corps optionnel] + +[footer optionnel] +``` + +### Types + +- `feat` : Nouvelle fonctionnalité +- `fix` : Correction de bug +- `docs` : Documentation uniquement +- `style` : Formatage, points-virgules manquants, etc. +- `refactor` : Refactoring sans changement de fonctionnalité +- `perf` : Amélioration de performance +- `test` : Ajout ou correction de tests +- `chore` : Maintenance, dépendances, etc. + +### Scopes (optionnel) + +- `api` : Backend +- `platform` : Frontend +- `metadata` : Package metadata +- `tools` : Outils de base de données +- `docs` : Documentation + +### Exemples + +```bash +# Nouvelle fonctionnalité +git commit -m "feat(platform): add dark mode toggle" + +# Correction de bug +git commit -m "fix(api): correct balance calculation in income statement" + +# Documentation +git commit -m "docs: update installation instructions" + +# Refactoring +git commit -m "refactor(api): extract email templates to separate files" + +# Maintenance +git commit -m "chore(deps): update drizzle to v0.45" +``` + +### Description + +- Utiliser l'impératif ("add" et non "added" ou "adds") +- Pas de majuscule au début +- Pas de point à la fin +- Maximum 72 caractères + +### Corps du commit (optionnel) + +Pour les changements complexes, ajoutez un corps explicatif : + +``` +feat(api): add export to Excel functionality + +Implement Excel export for financial statements using ExcelJS library. +Users can now export balance sheets and income statements. + +- Add ExcelJS dependency +- Create export utility functions +- Add export routes for both statement types +- Update documentation +``` + +## Process de pull request + +### 1. Vérifier avant de soumettre + +```bash +# Vérifier que tout compile +pnpm run build + +# Vérifier le linting (pour platform) +pnpm --filter platform run lint + +# Tester manuellement les changements +pnpm run dev +``` + +### 2. Mettre à jour votre branche + +```bash +# Récupérer les derniers changements +git fetch upstream +git rebase upstream/main +``` + +### 3. Pousser votre branche + +```bash +git push origin feature/ma-fonctionnalite +``` + +### 4. Créer la pull request + +Sur GitHub : +1. Cliquez sur "New Pull Request" +2. Sélectionnez votre branche +3. Remplissez le template de PR : + +```markdown +## Description +Brève description des changements + +## Type de changement +- [ ] Bug fix +- [ ] Nouvelle fonctionnalité +- [ ] Breaking change +- [ ] Documentation + +## Checklist +- [ ] Mon code suit les standards du projet +- [ ] J'ai commenté les parties complexes +- [ ] J'ai mis à jour la documentation si nécessaire +- [ ] Mes changements ne génèrent pas de nouveaux warnings +- [ ] J'ai testé localement + +## Screenshots (si applicable) +``` + +### 5. Attendre la review + +- Un mainteneur reviewera votre PR +- Répondez aux commentaires et effectuez les modifications demandées +- Une fois approuvée, votre PR sera mergée + +## Tests + +Actuellement, le projet n'a pas de suite de tests automatisés. Les contributions pour ajouter des tests sont bienvenues ! + +### Tests manuels requis + +Avant de soumettre une PR, testez manuellement : + +1. **Fonctionnalité ajoutée/modifiée** : Vérifiez qu'elle fonctionne comme prévu +2. **Régressions** : Vérifiez que vous n'avez rien cassé +3. **Cas limites** : Testez les edge cases (valeurs vides, très grandes, etc.) +4. **Différents navigateurs** : Chrome, Firefox, Safari (si frontend) + +### Tests futurs + +Nous prévoyons d'ajouter : +- Tests unitaires (Vitest) +- Tests d'intégration (Playwright) +- Tests E2E (Playwright) + +Les contributions dans ce sens sont encouragées ! + +## Code review + +### Pour les reviewers + +- Soyez constructif et respectueux +- Expliquez le "pourquoi" de vos suggestions +- Distinguez les suggestions obligatoires des optionnelles +- Approuvez si les changements sont satisfaisants + +### Pour les auteurs de PR + +- Ne prenez pas les commentaires personnellement +- Répondez à tous les commentaires (même avec "Done" ou "Fixed") +- Demandez des clarifications si nécessaire +- Remerciez les reviewers pour leur temps + +## Signaler un bug + +Pour signaler un bug, ouvrez une issue sur GitHub avec : + +### Titre +Résumé clair et concis du problème + +### Description +- **Description du bug** : Que se passe-t-il ? +- **Comportement attendu** : Que devrait-il se passer ? +- **Étapes pour reproduire** : + 1. Aller sur '...' + 2. Cliquer sur '...' + 3. Voir l'erreur +- **Screenshots** : Si applicable +- **Environnement** : + - OS : [ex: Ubuntu 22.04] + - Navigateur : [ex: Chrome 120] + - Version Node.js : [ex: 24.5.0] + - Version : [ex: commit SHA ou release] + +### Exemple + +```markdown +**Description** +Le calcul du compte de résultat affiche des montants négatifs incorrects. + +**Comportement attendu** +Les charges doivent apparaître en positif et être soustraites du résultat. + +**Étapes pour reproduire** +1. Créer un exercice comptable +2. Ajouter des écritures de charges +3. Consulter le compte de résultat +4. Observer que les montants sont négatifs + +**Screenshots** +[capture d'écran] + +**Environnement** +- OS: macOS 14.2 +- Navigateur: Firefox 121 +- Version: commit abc123 +``` + +## Proposer une fonctionnalité + +Pour proposer une nouvelle fonctionnalité, ouvrez une issue sur GitHub avec : + +### Titre +Description claire de la fonctionnalité + +### Description +- **Problème à résoudre** : Quel besoin cette fonctionnalité comble-t-elle ? +- **Solution proposée** : Comment voyez-vous cette fonctionnalité ? +- **Alternatives considérées** : Avez-vous pensé à d'autres approches ? +- **Contexte supplémentaire** : Captures d'écran, exemples d'autres apps, etc. + +### Exemple + +```markdown +**Problème** +Les utilisateurs ne peuvent pas exporter les données comptables pour les traiter dans Excel. + +**Solution proposée** +Ajouter un bouton "Exporter en Excel" sur chaque état financier qui génère un fichier .xlsx avec les données formatées. + +**Alternatives considérées** +- Export CSV : Moins convivial mais plus simple à implémenter +- Export PDF : Déjà disponible, mais pas éditable + +**Contexte** +Plusieurs utilisateurs ont demandé cette fonctionnalité pour faire des analyses complémentaires. +``` + +## Ressources additionnelles + +- [Documentation d'architecture](ARCHITECTURE.md) +- [Guide de développement](DEVELOPMENT.md) +- [Configuration](CONFIGURATION.md) +- [Issues GitHub](https://github.com/arrhes/arrhes-application/issues) +- [Discussions GitHub](https://github.com/arrhes/arrhes-application/discussions) + +## Questions ? + +Si vous avez des questions sur la contribution, n'hésitez pas à : +- Ouvrir une discussion sur GitHub +- Contacter les mainteneurs +- Consulter les issues et PR existantes + +Merci de contribuer à Arrhes ! 🎉 diff --git a/docs/DEVELOPMENT.md b/docs/DEVELOPMENT.md new file mode 100644 index 0000000..69431da --- /dev/null +++ b/docs/DEVELOPMENT.md @@ -0,0 +1,954 @@ +# Guide de développement + +Ce document vous guidera pour installer, configurer et développer Arrhes sur votre machine locale. + +## Table des matières + +- [Choix de l'environnement](#choix-de-lenvironnement) +- [Prérequis](#prérequis) +- [Installation](#installation) +- [Configuration](#configuration) +- [Initialisation de la base de données](#initialisation-de-la-base-de-données) +- [Lancement en développement](#lancement-en-développement) +- [Structure du projet](#structure-du-projet) +- [Scripts disponibles](#scripts-disponibles) +- [Workflow de développement](#workflow-de-développement) +- [Debugging](#debugging) +- [Conseils](#conseils) + +## Choix de l'environnement + +Vous avez trois options pour développer Arrhes : + +### Option 1 : Dev Container 🚀 (Le plus simple) + +**Avantages :** +- ✨ Configuration 100% automatique +- Environnement de développement complet dans un container +- Tous les services préconfigurés (PostgreSQL, RustFS, MailHog) +- Base de données initialisée automatiquement avec données de démo +- Extensions VS Code/Cursor installées automatiquement +- Zéro configuration manuelle + +**Prérequis :** +- Docker et Docker Compose +- VS Code ou Cursor avec l'extension "Dev Containers" + +**Idéal pour :** Nouveaux contributeurs, onboarding ultra-rapide, environnement unifié + +### Option 2 : Développement avec Docker Compose 🐳 + +**Avantages :** +- Configuration simplifiée (pas d'installation de PostgreSQL, RustFS, etc.) +- Environnement standardisé et reproductible +- Isolation complète des services +- Node.js et pnpm installés localement (meilleure performance) + +**Prérequis :** +- Node.js 24.5+ +- pnpm +- Docker et Docker Compose + +**Idéal pour :** Développement quotidien, bonne balance performance/simplicité + +### Option 3 : Développement natif + +**Avantages :** +- Contrôle total sur chaque service +- Peut être plus rapide sur certaines machines +- Pas besoin de Docker + +**Prérequis :** +- Node.js 24.5+ +- pnpm +- PostgreSQL installé localement +- Optionnellement Docker pour RustFS et MailHog + +**Idéal pour :** Développeurs expérimentés, personnalisation avancée + +--- + +**💡 Conseil :** +- **Première contribution ?** → Choisissez l'**Option 1 (Dev Container)** pour démarrer en 2 minutes +- **Développement quotidien ?** → Choisissez l'**Option 2 (Docker Compose)** pour la meilleure expérience + +## Prérequis + +### Option 1 : Dev Container + +- **Docker** et **Docker Compose** : https://www.docker.com/get-started + ```bash + docker --version + docker-compose --version + ``` + +- **VS Code** ou **Cursor** avec l'extension Dev Containers : + - VS Code : https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers + - Cursor : Installer depuis le marketplace d'extensions + +C'est tout ! Node.js, pnpm, PostgreSQL, RustFS et MailHog seront configurés automatiquement dans le container. + +### Prérequis communs (Options 2 et 3) + +- **Node.js** : Version 24.5 ou supérieure + ```bash + node --version # Devrait afficher v24.5.x ou supérieur + ``` + + Installation : https://nodejs.org/ + +- **pnpm** : Version 9 ou supérieure + ```bash + pnpm --version + ``` + + Installation : + ```bash + npm install -g pnpm + # ou + curl -fsSL https://get.pnpm.io/install.sh | sh - + ``` + +### Option 2 : Avec Docker Compose + +- **Docker** et **Docker Compose** : https://www.docker.com/get-started + ```bash + docker --version + docker-compose --version + ``` + +C'est tout ! PostgreSQL, RustFS et MailHog seront lancés automatiquement dans des containers. + +### Option 3 : Développement natif + +- **PostgreSQL** : Version 14 ou supérieure recommandée + ```bash + psql --version + ``` + + **Installation :** + + **Ubuntu/Debian :** + ```bash + sudo apt update + sudo apt install postgresql postgresql-contrib + sudo systemctl start postgresql + ``` + + **macOS :** + ```bash + brew install postgresql@16 + brew services start postgresql@16 + ``` + + **Windows :** + Télécharger depuis https://www.postgresql.org/download/windows/ + +- **Docker** (optionnel, pour RustFS et MailHog) : https://www.docker.com/get-started +- Ou configurez des services S3 et SMTP alternatifs + +## Installation + +### Option 1 : Avec Dev Container 🚀 + +**Étape 1 : Cloner le repository** + +```bash +git clone https://github.com/arrhes/arrhes-application.git +cd arrhes-application +``` + +**Étape 2 : Ouvrir dans VS Code/Cursor** + +```bash +# Avec VS Code +code . + +# Avec Cursor +cursor . +``` + +**Étape 3 : Reopen in Container** + +Lorsque VS Code/Cursor détecte le fichier `.development/devcontainer.json`, une notification apparaît : + +> "Folder contains a Dev Container configuration file. Reopen folder to develop in a container?" + +Cliquez sur **"Reopen in Container"** ou utilisez la palette de commandes : +- `Cmd/Ctrl + Shift + P` +- Tapez "Dev Containers: Reopen in Container" +- Appuyez sur Entrée + +**Ce qui se passe automatiquement :** +1. 🐳 Construction du container de développement +2. 📦 Installation de toutes les dépendances (pnpm install) +3. 🚀 Démarrage de PostgreSQL, RustFS et MailHog +4. ⏳ Attente que PostgreSQL soit prêt +5. 🗄️ Création du schéma de base de données +6. 🌱 Insertion des données de démonstration +7. ⚙️ Création automatique des fichiers `.env` +8. 🎨 Installation des extensions VS Code recommandées + +**Étape 4 : Lancer l'application** + +Une fois le container prêt (vous verrez "✨ Configuration terminée !" dans le terminal) : + +```bash +pnpm run dev +``` + +C'est tout ! Vous êtes prêt à développer. 🎉 + +**URLs d'accès :** +- **Platform** : http://localhost:5173 +- **API** : http://localhost:3000 +- **RustFS Console** : http://localhost:9001 (arrhes_rustfs / arrhes_rustfs_secret) +- **MailHog** : http://localhost:8025 + +**Identifiants de démonstration :** +- Email : `demo@arrhes.com` +- Mot de passe : `demo` + +--- + +### Option 2 : Avec Docker Compose 🐳 + +**Étape 1 : Cloner le repository** + +```bash +git clone https://github.com/arrhes/arrhes-application.git +cd arrhes-application +``` + +**Étape 2 : Installer les dépendances** + +```bash +pnpm install +``` + +Cette commande installera toutes les dépendances de tous les packages du monorepo. + +**Étape 3 : Vérifier l'installation** + +```bash +pnpm ls --depth=0 +``` + +Vous devriez voir tous les packages workspace listés. + +--- + +### Option 3 : Installation native + +**Étape 1 : Cloner le repository** + +```bash +git clone https://github.com/arrhes/arrhes-application.git +cd arrhes-application +``` + +**Étape 2 : Installer les dépendances** + +```bash +pnpm install +``` + +**Étape 3 : Vérifier l'installation** + +```bash +pnpm ls --depth=0 +``` + +## Configuration + +### Option 1 : Avec Dev Container 🚀 + +**Aucune configuration manuelle nécessaire !** + +Le script `post-create.sh` s'exécute automatiquement et crée les fichiers `.env` avec les bonnes valeurs pour l'environnement containerisé. + +Les fichiers suivants sont créés automatiquement : +- `packages/api/.env` (avec connexion aux services Docker) +- `packages/tools/.env` (avec connexion à PostgreSQL) + +**Note importante :** Dans le Dev Container, les URLs pointent vers les noms de services Docker : +- PostgreSQL : `postgres:5432` (au lieu de `localhost:5432`) +- RustFS : `rustfs:9000` (au lieu de `localhost:9000`) +- MailHog : `mailhog:1025` (au lieu de `localhost:1025`) + +Si vous souhaitez modifier la configuration, éditez directement les fichiers `.env` créés. + +--- + +### Option 2 : Configuration avec Docker Compose 🐳 + +#### 1. Lancer les services avec Docker Compose + +```bash +# Lancer tous les services (PostgreSQL, RustFS, MailHog) +docker-compose up -d + +# Vérifier que tout fonctionne +docker-compose ps +``` + +Les services seront disponibles sur : +- **PostgreSQL** : `localhost:5432` +- **RustFS API** : `localhost:9000` +- **RustFS Console** : http://localhost:9001 +- **MailHog SMTP** : `localhost:1025` +- **MailHog Web** : http://localhost:8025 + +#### 2. Créer le bucket RustFS + +```bash +# Accéder à la console RustFS : http://localhost:9001 +# Credentials : arrhes_rustfs / arrhes_rustfs_secret +# Créer un bucket nommé "arrhes-files" +``` + +Ou via la ligne de commande : +```bash +# Installer le client RustFS +# Create the bucket via the RustFS web UI at http://localhost:9001 or use an S3-compatible client to create `arrhes-files`. +``` + +#### 3. Créer les fichiers de configuration + +**`packages/api/.env` :** + +```bash +cd packages/api +cat > .env << 'EOF' +# Environnement +ENV=development +VERBOSE=true +PORT=3000 + +# CORS et Cookies +CORS_ORIGIN=http://localhost:5173 +COOKIES_DOMAIN=localhost +COOKIES_KEY=development-secret-key-change-in-production-min-32-chars + +# URLs +API_BASE_URL=http://localhost:3000 +PLATFORM_BASE_URL=http://localhost:5173 +WEBSITE_BASE_URL=http://localhost:5174 + +# Base de données (Docker Compose) +SQL_DATABASE_URL=postgres://arrhes_user:arrhes_password@localhost:5432/arrhes + +# Stockage RustFS (Docker Compose) +STORAGE_ENDPOINT=http://localhost:9000 +STORAGE_BUCKET_NAME=arrhes-files +STORAGE_ACCESS_KEY=arrhes_rustfs +STORAGE_SECRET_KEY=arrhes_rustfs_secret + +# Email MailHog (Docker Compose) +EMAIL_ENDPOINT=localhost:1025 +EMAIL_USER=test +EMAIL_PASSWORD=test +EOF +cd ../.. +``` + +**`packages/tools/.env` :** + +```bash +cd packages/tools +cat > .env << 'EOF' +DATABASE_URL=postgres://arrhes_user:arrhes_password@localhost:5432/arrhes +EOF +cd ../.. +``` + +--- + +### Option 2 : Configuration native + +#### 1. Créer la base de données PostgreSQL + +```bash +# Se connecter à PostgreSQL +sudo -u postgres psql + +# Dans le shell PostgreSQL : +CREATE USER arrhes_user WITH PASSWORD 'arrhes_password'; +CREATE DATABASE arrhes OWNER arrhes_user; +GRANT ALL PRIVILEGES ON DATABASE arrhes TO arrhes_user; +\q +``` + +#### 2. Configurer les services externes (optionnel) + +**RustFS (Stockage de fichiers) :** + +```bash +# Lancer RustFS avec Docker +docker run -d \ + -p 9000:9000 \ + -p 9001:9001 \ + --name rustfs \ + + -e "RUSTFS_ROOT_USER=arrhes_rustfs" \ + -e "RUSTFS_ROOT_PASSWORD=arrhes_rustfs_secret" \ + -v ~/rustfs/data:/data \ + rustfs/rustfs:latest server /data --web-ui-address ":9001" + +# Accéder à la web UI : http://localhost:9001 +# Créer un bucket nommé "arrhes-files" +``` + +**MailHog (Test d'emails) :** + +```bash +# Lancer MailHog avec Docker +docker run -d -p 1025:1025 -p 8025:8025 mailhog/mailhog + +# Interface web : http://localhost:8025 +``` + +#### 3. Créer les fichiers de configuration + +Utilisez les mêmes commandes que dans l'Option 1, étape 3 ci-dessus. + +--- + +**Pour plus de détails sur la configuration, consultez [CONFIGURATION.md](CONFIGURATION.md).** + +## Initialisation de la base de données + +### Option 1 : Avec Dev Container 🚀 + +**Aucune action nécessaire !** + +La base de données est automatiquement initialisée lors de la création du container. Le script `post-create.sh` exécute : +1. `pnpm --filter tools run push` (création du schéma) +2. `pnpm --filter tools run seed` (insertion des données de démo) + +Si vous souhaitez réinitialiser la base : +```bash +pnpm --filter tools run reset +``` + +--- + +### Options 2 et 3 : Configuration manuelle + +**Étape 1 : Pousser le schéma vers la base de données** + +```bash +pnpm --filter tools run push +``` + +Cette commande crée toutes les tables nécessaires dans PostgreSQL à partir des schémas définis dans `@arrhes/application-metadata`. + +**Étape 2 : Seed avec des données de démonstration** + +```bash +pnpm --filter tools run seed +``` + +Cette commande insère : +- Un utilisateur de démonstration : `demo@arrhes.com` / `demo` +- Une organisation exemple : "Arrhes" +- Des comptes comptables de base +- Des journaux +- Des écritures comptables d'exemple pour 2022 et 2023 +- Des documents et états financiers + +**Étape 3 : Réinitialiser la base (si nécessaire)** + +Pour tout supprimer et recommencer : + +```bash +pnpm --filter tools run reset +``` + +Cette commande exécute : `clear` + `push` + `seed` + +## Lancement en développement + +### Commande principale (toutes options) + +```bash +pnpm run dev +``` + +Cette commande lance simultanément : +- **API** sur http://localhost:3000 +- **Platform** sur http://localhost:5173 + +Les deux processus tournent en parallèle avec hot-reload activé. + +### Lancer individuellement (optionnel) + +Dans des terminaux séparés : + +**Terminal 1 - API :** +```bash +pnpm --filter api run dev +``` + +**Terminal 2 - Platform :** +```bash +pnpm --filter platform run dev +``` + +**Terminal 3 - Metadata (optionnel, watch mode) :** +```bash +pnpm --filter metadata run dev +``` + +### Accès à l'application + +- **Frontend (Platform)** : http://localhost:5173 +- **API** : http://localhost:3000 +- **RustFS Console** : http://localhost:9001 (arrhes_rustfs / arrhes_rustfs_secret) +- **MailHog Web UI** : http://localhost:8025 + +### Identifiants de démonstration + +``` +Email : demo@arrhes.com +Password : demo +``` + +### Notes par option + +**Dev Container :** +- Les services (PostgreSQL, RustFS, MailHog) sont déjà démarrés automatiquement +- Les ports sont automatiquement forwardés vers votre machine locale +- Vous pouvez cliquer sur les ports dans VS Code/Cursor pour ouvrir les URLs + +**Docker Compose :** +- Assurez-vous que les services sont lancés : `docker-compose ps` +- Si les services ne sont pas démarrés : `docker-compose up -d` + +**Natif :** +- Assurez-vous que PostgreSQL est démarré +- Si vous utilisez RustFS/MailHog avec Docker, vérifiez qu'ils tournent : `docker ps` + +## Structure du projet + +``` +arrhes/ +├── packages/ +│ ├── api/ # Backend API +│ │ ├── src/ +│ │ │ ├── api.ts # Configuration Hono +│ │ │ ├── server.ts # Point d'entrée +│ │ │ ├── clients/ # Clients services externes +│ │ │ ├── factories/ # Factories Hono typées +│ │ │ ├── middlewares/ # Auth, validation, etc. +│ │ │ ├── routes/ # Routes API +│ │ │ │ ├── auth/ # Routes authentifiées +│ │ │ │ └── public/ # Routes publiques +│ │ │ └── utilities/ # Utilitaires +│ │ ├── .env # Variables d'environnement +│ │ ├── package.json +│ │ └── tsconfig.json +│ │ +│ ├── platform/ # Frontend React +│ │ ├── src/ +│ │ │ ├── root.tsx # Point d'entrée React +│ │ │ ├── index.html # HTML principal +│ │ │ ├── assets/ # CSS, fonts, images +│ │ │ ├── components/ # Composants UI réutilisables +│ │ │ ├── contexts/ # React contexts +│ │ │ ├── features/ # Features par domaine +│ │ │ ├── routes/ # Définition routes +│ │ │ └── utilities/ # Utilitaires +│ │ ├── package.json +│ │ ├── tsconfig.json +│ │ └── vite.config.ts +│ │ +│ ├── metadata/ # Schémas et types partagés +│ │ ├── src/ +│ │ │ ├── models/ # Modèles Drizzle ORM +│ │ │ ├── schemas/ # Schémas Valibot +│ │ │ ├── routes/ # Définitions routes API +│ │ │ ├── components/ # Composants métier +│ │ │ └── utilities/ # Utilitaires +│ │ ├── package.json +│ │ └── tsconfig.json +│ │ +│ ├── tools/ # Outils base de données +│ │ ├── src/ +│ │ │ ├── clearDB.ts # Vider la DB +│ │ │ ├── migrate.ts # Migrations +│ │ │ ├── schemas.ts # Import schémas +│ │ │ └── seed/ # Scripts de seed +│ │ ├── .env # Variables d'environnement +│ │ ├── drizzle.config.ts # Config Drizzle Kit +│ │ ├── package.json +│ │ └── tsconfig.json +│ │ +│ └── website/ # Site vitrine +│ ├── src/ +│ ├── package.json +│ └── vite.config.ts +│ +├── docs/ # Documentation +│ ├── ARCHITECTURE.md +│ ├── CONFIGURATION.md +│ ├── DEVELOPMENT.md +│ └── CONTRIBUTING.md +│ +├── pnpm-workspace.yaml # Configuration workspace +├── package.json # Scripts racine +├── tsconfig.json # Config TypeScript globale +├── LICENSE +└── README.md +``` + +## Scripts disponibles + +### Scripts racine (depuis `/`) + +```bash +# Lancer API + Platform en développement +pnpm run dev + +# Builder tous les packages +pnpm run build +``` + +### Scripts API (`packages/api/`) + +```bash +# Développement avec hot-reload +pnpm --filter api run dev + +# Build pour production +pnpm --filter api run build + +# Lancer en production (après build) +pnpm --filter api run start +``` + +### Scripts Platform (`packages/platform/`) + +```bash +# Développement avec hot-reload +pnpm --filter platform run dev + +# Build pour production +pnpm --filter platform run build + +# Linter +pnpm --filter platform run lint +``` + +### Scripts Metadata (`packages/metadata/`) + +```bash +# Build avec watch mode +pnpm --filter metadata run dev + +# Build une fois +pnpm --filter metadata run build +``` + +### Scripts Tools (`packages/tools/`) + +```bash +# Générer les migrations depuis le schéma +pnpm --filter tools run generate + +# Pousser le schéma vers la DB (dev) +pnpm --filter tools run push + +# Appliquer les migrations (production) +pnpm --filter tools run migrate + +# Seed avec données de démo +pnpm --filter tools run seed + +# Vider complètement la DB +pnpm --filter tools run clear + +# Reset complet : clear + push + seed +pnpm --filter tools run reset + +# Supprimer les migrations +pnpm --filter tools run drop +``` + +## Workflow de développement + +### Développement typique + +#### Avec Docker Compose 🐳 + +1. **Lancer les services** + ```bash + # Lancer tous les services (PostgreSQL, RustFS, MailHog) + docker-compose up -d + ``` + +2. **Lancer l'application** + ```bash + pnpm run dev + ``` + +3. **Développer avec hot-reload** + - Modifications dans `packages/api/src/` → Rechargement automatique de l'API + - Modifications dans `packages/platform/src/` → HMR (Hot Module Replacement) + - Modifications dans `packages/metadata/src/` → Nécessite rebuild (ou mode watch) + +4. **Arrêter les services (à la fin de la session)** + ```bash + # Arrêter sans supprimer les données + docker-compose stop + + # Ou arrêter et supprimer les containers (garde les volumes) + docker-compose down + + # Ou tout supprimer (containers + volumes = perte de données) + docker-compose down -v + ``` + +#### Avec installation native + +1. **Lancer les services externes** + ```bash + # PostgreSQL (si pas démarré) + sudo systemctl start postgresql + + # RustFS (si utilisé avec Docker) + docker start rustfs + + # MailHog (si utilisé avec Docker) + docker start mailhog + ``` + +2. **Lancer l'application** + ```bash + pnpm run dev + ``` + +3. **Développer avec hot-reload** + - Modifications dans `packages/api/src/` → Rechargement automatique de l'API + - Modifications dans `packages/platform/src/` → HMR (Hot Module Replacement) + - Modifications dans `packages/metadata/src/` → Nécessite rebuild (ou mode watch) + +### Modifier le schéma de base de données + +1. **Modifier les modèles** dans `packages/metadata/src/models/` + +2. **Rebuild metadata** + ```bash + pnpm --filter metadata run build + ``` + +3. **Générer la migration** (optionnel, pour production) + ```bash + pnpm --filter tools run generate + ``` + +4. **Appliquer les changements** + ```bash + # Développement : push direct + pnpm --filter tools run push + + # Production : migrations + pnpm --filter tools run migrate + ``` + +5. **Mettre à jour le seed** si nécessaire dans `packages/tools/src/seed/` + +### Ajouter une nouvelle route API + +1. **Créer la définition de route** dans `packages/metadata/src/routes/` + ```typescript + // packages/metadata/src/routes/auth/myFeature.ts + import { routeDefinition } from '#src/utilities/routeDefinition.js' + import * as v from 'valibot' + + export const myFeatureRoute = routeDefinition({ + path: '/api/auth/my-feature', + paramsSchema: v.object({ /* ... */ }), + bodySchema: v.object({ /* ... */ }), + responseSchema: v.object({ /* ... */ }), + }) + ``` + +2. **Créer l'implémentation** dans `packages/api/src/routes/auth/` + ```typescript + // packages/api/src/routes/auth/myFeature.ts + import { myFeatureRoute } from '@arrhes/application-metadata/routes' + import { authFactory } from '#/factories/authFactory.js' + + export const myFeature = authFactory.createApp().post( + myFeatureRoute.path, + async (c) => { + // Implémentation + return c.json({ /* ... */ }) + } + ) + ``` + +3. **Enregistrer la route** dans `packages/api/src/routes/routes.ts` + +4. **Utiliser côté frontend** dans `packages/platform/src/utilities/postAPI.ts` + +### Ajouter une nouvelle page + +1. **Créer le composant** dans `packages/platform/src/features/` + +2. **Définir la route** dans `packages/platform/src/routes/root/` + +3. **Mettre à jour le tree** dans `packages/platform/src/routes/platformTree.ts` + +4. **Ajouter la navigation** si nécessaire dans les layouts + +## Debugging + +### API (Backend) + +**Logs verbeux :** +```env +VERBOSE=true +``` + +**Debugger Node.js :** + +Modifier `packages/api/package.json` : +```json +{ + "scripts": { + "dev:debug": "tsx watch --inspect --env-file=.env ./src/server.ts" + } +} +``` + +Lancer : +```bash +pnpm --filter api run dev:debug +``` + +Attacher le debugger dans VS Code avec cette configuration (`.vscode/launch.json`) : +```json +{ + "type": "node", + "request": "attach", + "name": "Attach to API", + "port": 9229, + "skipFiles": ["/**"] +} +``` + +### Platform (Frontend) + +**Console du navigateur :** +- Ouvrir DevTools (F12) +- Voir les erreurs, warnings, et logs + +**React DevTools :** +- Installer l'extension React DevTools +- Inspecter les composants et leur state + +**TanStack Query DevTools :** +Déjà intégré dans l'application, visible en bas de l'écran en mode dev. + +### Base de données + +**Inspecter la DB :** +```bash +psql postgres://arrhes_user:arrhes_password@localhost:5432/arrhes +``` + +**Commandes SQL utiles :** +```sql +-- Lister les tables +\dt + +-- Voir le schéma d'une table +\d table_name + +-- Compter les enregistrements +SELECT COUNT(*) FROM users; + +-- Voir les derniers enregistrements +SELECT * FROM users ORDER BY "createdAt" DESC LIMIT 10; +``` + +**Drizzle Studio** (GUI pour visualiser la DB) : +```bash +pnpm dlx drizzle-kit studio --config=packages/tools/drizzle.config.ts +``` + +## Conseils + +### Performance + +- **Hot-reload lent ?** Redémarrez le serveur de développement +- **Build lent ?** Vérifiez que Node.js est à jour +- **pnpm lent ?** Nettoyez le cache : `pnpm store prune` + +### Problèmes courants + +**"Cannot connect to database" :** +- **Avec Docker :** Vérifiez que les containers sont lancés : `docker-compose ps` +- **Natif :** Vérifiez que PostgreSQL est démarré : `sudo systemctl status postgresql` +- Testez la connexion : `psql postgres://arrhes_user:arrhes_password@localhost:5432/arrhes` +- Vérifiez les credentials dans `.env` + +**"Module not found @arrhes/application-metadata" :** +- Rebuild metadata : `pnpm --filter metadata run build` +- Ou lancez en mode watch : `pnpm --filter metadata run dev` + +**"CORS error" :** +- Vérifiez `CORS_ORIGIN` dans `packages/api/.env` +- Assurez-vous que l'URL correspond exactement + +**"Cookie not set" :** +- Vérifiez `COOKIES_DOMAIN` (doit être `localhost` en dev) +- Vérifiez que l'API et la platform sont sur le même domaine + +**"S3/Storage error" :** +- Vérifiez que RustFS est démarré : `docker ps | grep rustfs` +- Vérifiez que le bucket existe (console : http://localhost:9001) +- Testez l'endpoint : `curl http://localhost:9000/health || curl http://localhost:9000/health/live` + +**Problèmes Docker :** +- **Port déjà utilisé :** Un autre service utilise le même port + ```bash + # Voir ce qui utilise le port 5432 (PostgreSQL) + sudo lsof -i :5432 + # Ou arrêter l'autre service + ``` +- **Container ne démarre pas :** Voir les logs + ```bash + docker-compose logs postgres + docker-compose logs rustfs + docker-compose logs mailhog + ``` +- **Réinitialiser complètement :** + ```bash + docker-compose down -v + docker-compose up -d + ``` + +### Bonnes pratiques + +1. **Commits atomiques** : Un commit = une fonctionnalité/fix +2. **Messages de commit clairs** : Suivez les conventions (voir CONTRIBUTING.md) +3. **Tester avant de commit** : Vérifiez que tout fonctionne +4. **Suivre les patterns existants** : Regardez le code existant pour rester cohérent +5. **Documenter les changements** : Commentaires pour la logique complexe + +### Ressources utiles + +- **Hono** : https://hono.dev/ +- **Drizzle ORM** : https://orm.drizzle.team/ +- **Valibot** : https://valibot.dev/ +- **TanStack Router** : https://tanstack.com/router/ +- **TanStack Query** : https://tanstack.com/query/ +- **Radix UI** : https://www.radix-ui.com/ +- **Panda CSS** : https://panda-css.com/ + +--- + +Pour contribuer au projet, consultez [CONTRIBUTING.md](CONTRIBUTING.md). diff --git a/justfile b/justfile new file mode 100644 index 0000000..a2c2fab --- /dev/null +++ b/justfile @@ -0,0 +1,41 @@ +set shell := ["bash", "-cu"] +COMPOSE_FILE := ".development/compose.yml" +PROJECT := "arrhes-application" + +dev cmd: + @just dev-{{cmd}} + +dev-up: + docker compose --project-directory=".development" --file="{{COMPOSE_FILE}}" --project-name="{{PROJECT}}" up -d --build + @echo "" + @echo "==============================================" + @echo " Arrhes Development Environment Started" + @echo "==============================================" + @echo "" + @echo " Services:" + @echo " Dashboard: http://localhost:5173" + @echo " API: http://localhost:3000" + @echo "" + @echo " Infrastructure:" + @echo " PostgreSQL: localhost:5432" + @echo " Mailpit: http://localhost:8025" + @echo " RustFS: http://localhost:9001" + @echo "" + @echo " Demo Credentials:" + @echo " Email: demo@arrhes.com" + @echo " Password: demo" + @echo "" + @echo " Logs: docker compose -f {{COMPOSE_FILE}} logs -f" + @echo "==============================================" + +dev-down: + docker ps -a --filter="name=arrhes-" -q | xargs -r docker rm -f + docker compose --project-directory=".development" --file="{{COMPOSE_FILE}}" --project-name="{{PROJECT}}" down + +dev-reset: + @echo "Resetting database (clearing and reseeding)..." + docker compose --project-directory=".development" --file="{{COMPOSE_FILE}}" --project-name="{{PROJECT}}" exec api sh -c "cd /workspace/packages/tools && pnpm run reset" + @echo "Database reset complete." + +dev-logs: + docker compose --project-directory=".development" --file="{{COMPOSE_FILE}}" --project-name="{{PROJECT}}" logs -f diff --git a/package.json b/package.json index e605d18..e785666 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,7 @@ "name": "arrhes", "version": "1.0.0", "private": true, + "license": "AGPL-3.0-only", "scripts": { "dev": "pnpm --recursive --if-present --parallel --filter='./packages/**' run dev", "build": "pnpm --recursive --if-present --filter='./packages/**' run build" diff --git a/packages/api/package.json b/packages/api/package.json index 701300f..d779f43 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -1,5 +1,5 @@ { - "name": "@arrhes/api", + "name": "@arrhes/application-api", "type": "module", "private": false, "scripts": { @@ -14,7 +14,7 @@ "typescript": "5.9.3" }, "dependencies": { - "@arrhes/metadata": "workspace:*", + "@arrhes/application-metadata": "workspace:*", "@aws-sdk/client-s3": "3.940.0", "@aws-sdk/s3-request-presigner": "3.940.0", "drizzle-orm": "0.44.7", diff --git a/packages/api/src/api.ts b/packages/api/src/api.ts index c3788f3..3996fc7 100644 --- a/packages/api/src/api.ts +++ b/packages/api/src/api.ts @@ -1,10 +1,10 @@ -import { apiFactory } from "#/factories/apiFactory.js" -import { routes } from "#/routes/routes.js" -import { apiLog } from "#/utilities/apiLog.js" -import { Exception } from "#/utilities/exception.js" -import { getClients } from "#/utilities/getClients.js" -import { getEnv } from "#/utilities/getEnv.js" -import { response } from "#/utilities/response.js" +import { apiFactory } from "./factories/apiFactory.js" +import { routes } from "./routes/routes.js" +import { apiLog } from "./utilities/apiLog.js" +import { Exception } from "./utilities/exception.js" +import { getClients } from "./utilities/getClients.js" +import { getEnv } from "./utilities/getEnv.js" +import { response } from "./utilities/response.js" import { cors } from "hono/cors" import { logger } from "hono/logger" import pg from "postgres" diff --git a/packages/api/src/clients/emailClient.ts b/packages/api/src/clients/emailClient.ts index a9023a4..0d040da 100644 --- a/packages/api/src/clients/emailClient.ts +++ b/packages/api/src/clients/emailClient.ts @@ -1,31 +1,31 @@ -import { Exception } from "#/utilities/exception.js" -import { getEnv } from "#/utilities/getEnv.js" -import { createTransport } from "nodemailer" - - -export function emailClient(env: ReturnType) { - try { - const smtpClient = createTransport({ - host: env.EMAIL_ENDPOINT, - port: 465, - secure: true, - auth: { - user: env.EMAIL_USER, - pass: env.EMAIL_PASSWORD - } - }, - { - from: "Arrhes " - } - ) - - return smtpClient - } - catch (error) { - throw new Exception({ - statusCode: 500, - internalMessage: "SQL client not available", - rawError: error, - }) - } +import { Exception } from "../utilities/exception.js" +import { getEnv } from "../utilities/getEnv.js" +import { createTransport } from "nodemailer" + + +export function emailClient(env: ReturnType) { + try { + const smtpClient = createTransport({ + host: env.EMAIL_ENDPOINT, + port: 465, + secure: true, + auth: { + user: env.EMAIL_USER, + pass: env.EMAIL_PASSWORD + } + }, + { + from: "Arrhes " + } + ) + + return smtpClient + } + catch (error) { + throw new Exception({ + statusCode: 500, + internalMessage: "SQL client not available", + rawError: error, + }) + } } \ No newline at end of file diff --git a/packages/api/src/clients/sqlClient.ts b/packages/api/src/clients/sqlClient.ts index 95d24a2..b8cc753 100644 --- a/packages/api/src/clients/sqlClient.ts +++ b/packages/api/src/clients/sqlClient.ts @@ -1,21 +1,21 @@ -import { Exception } from "#/utilities/exception.js" -import { getEnv } from "#/utilities/getEnv.js" -import { modelSchemas } from "@arrhes/metadata/models" -import { drizzle } from 'drizzle-orm/postgres-js' -import postgres from "postgres" - - -export function sqlClient(env: ReturnType) { - try { - const queryClient = postgres(env.SQL_DATABASE_URL) - const db = drizzle(queryClient, { schema: modelSchemas }) - return db - } - catch (error) { - throw new Exception({ - statusCode: 500, - internalMessage: "SQL client not available", - rawError: error, - }) - } +import { Exception } from "../utilities/exception.js" +import { getEnv } from "../utilities/getEnv.js" +import { modelSchemas } from "@arrhes/application-metadata/models" +import { drizzle } from 'drizzle-orm/postgres-js' +import postgres from "postgres" + + +export function sqlClient(env: ReturnType) { + try { + const queryClient = postgres(env.SQL_DATABASE_URL) + const db = drizzle(queryClient, { schema: modelSchemas }) + return db + } + catch (error) { + throw new Exception({ + statusCode: 500, + internalMessage: "SQL client not available", + rawError: error, + }) + } } \ No newline at end of file diff --git a/packages/api/src/clients/storageClient.ts b/packages/api/src/clients/storageClient.ts index 7769f0f..d25a234 100644 --- a/packages/api/src/clients/storageClient.ts +++ b/packages/api/src/clients/storageClient.ts @@ -1,25 +1,25 @@ -import { Exception } from "#/utilities/exception.js" -import { getEnv } from "#/utilities/getEnv.js" -import { S3 } from "@aws-sdk/client-s3" - - -export function storageClient(env: ReturnType) { - try { - const storageClient = new S3({ - endpoint: env.STORAGE_ENDPOINT, - credentials: { - accessKeyId: env.STORAGE_ACCESS_KEY, - secretAccessKey: env.STORAGE_SECRET_KEY, - }, - region: "fr-par" - }) - return storageClient - } - catch (error) { - throw new Exception({ - statusCode: 500, - internalMessage: "Storage client not available", - rawError: error, - }) - } +import { Exception } from "../utilities/exception.js" +import { getEnv } from "../utilities/getEnv.js" +import { S3 } from "@aws-sdk/client-s3" + + +export function storageClient(env: ReturnType) { + try { + const storageClient = new S3({ + endpoint: env.STORAGE_ENDPOINT, + credentials: { + accessKeyId: env.STORAGE_ACCESS_KEY, + secretAccessKey: env.STORAGE_SECRET_KEY, + }, + region: "fr-par" + }) + return storageClient + } + catch (error) { + throw new Exception({ + statusCode: 500, + internalMessage: "Storage client not available", + rawError: error, + }) + } } \ No newline at end of file diff --git a/packages/api/src/factories/apiFactory.ts b/packages/api/src/factories/apiFactory.ts index 4f50559..593353e 100644 --- a/packages/api/src/factories/apiFactory.ts +++ b/packages/api/src/factories/apiFactory.ts @@ -1,5 +1,5 @@ -import { getClients } from "#/utilities/getClients.js" -import { getEnv } from "#/utilities/getEnv.js" +import { getClients } from "../utilities/getClients.js" +import { getEnv } from "../utilities/getEnv.js" import { Env } from "hono" import { createFactory } from "hono/factory" diff --git a/packages/api/src/factories/authFactory.ts b/packages/api/src/factories/authFactory.ts index 37cd54c..7302a34 100644 --- a/packages/api/src/factories/authFactory.ts +++ b/packages/api/src/factories/authFactory.ts @@ -1,5 +1,5 @@ -import { ApiEnv } from "#/factories/apiFactory.js" -import { models } from "@arrhes/metadata/models" +import { ApiEnv } from "../factories/apiFactory.js" +import { models } from "@arrhes/application-metadata/models" import { createFactory } from "hono/factory" diff --git a/packages/api/src/factories/publicFactory.ts b/packages/api/src/factories/publicFactory.ts index fd35d44..0a6f14c 100644 --- a/packages/api/src/factories/publicFactory.ts +++ b/packages/api/src/factories/publicFactory.ts @@ -1,4 +1,4 @@ -import { ApiEnv } from "#/factories/apiFactory.js" +import { ApiEnv } from "../factories/apiFactory.js" import { createFactory } from "hono/factory" diff --git a/packages/api/src/middlewares/authMiddleware.ts b/packages/api/src/middlewares/authMiddleware.ts index ca9e030..c33de75 100644 --- a/packages/api/src/middlewares/authMiddleware.ts +++ b/packages/api/src/middlewares/authMiddleware.ts @@ -1,93 +1,92 @@ -import { AuthEnv } from "#/factories/authFactory.js" -import { parseCookies } from "#/utilities/cookies/parseCookies.js" -import { unsignString } from "#/utilities/cookies/unsignString.js" -import { Exception } from "#/utilities/exception.js" -import { selectOne } from "#/utilities/sql/selectOne.js" -import { cookiePrefix } from "#/utilities/variables.js" -import { models } from "@arrhes/metadata/models" -import { eq } from "drizzle-orm" -import { createMiddleware } from "hono/factory" - - -export const authMiddleware = createMiddleware(async (c, next) => { - try { - const cookies = parseCookies({ value: c.req.header("Cookie") }) - const idUserSession = unsignString({ - signedValue: cookies[`${cookiePrefix}_${"id_user_session"}`], - secret: c.var.env.COOKIES_KEY, - }) - - if (idUserSession === undefined) { - throw new Exception({ - internalMessage: "Auth error", - cause: "id_user_session not found in signed cookie", - }) - } - - const userSession = await selectOne({ - database: c.var.clients.sql, - table: models.userSession, - where: (table) => ( - eq(table.id, idUserSession) - ) - }) - if (userSession.isActive === false) { - throw new Exception({ - internalMessage: "Auth error", - cause: "userSession.isActive is false" - }) - } - c.set("userSession", userSession) - - - const user = await selectOne({ - database: c.var.clients.sql, - table: models.user, - where: (table) => ( - eq(table.id, userSession.idUser) - ) - }) - c.set("user", user) - - await next() - } - catch (error: unknown) { - - // c.res.headers.append( - // "Set-Cookie", - // serializeCookie({ - // name: `${cookiePrefix}_${"id_user_session"}`, - // value: "", - // options: { - // maxAge: userSessionCookieMaxAge, - // httpOnly: true, - // secure: true, - // sameSite: "None", - // domain: c.var.env.COOKIES_DOMAIN, - // path: "/", - // } - // }) - // ) - // c.res.headers.append( - // "Set-Cookie", - // serializeCookie({ - // name: `${cookiePrefix}_${"is_auth"}`, - // value: String(false), - // options: { - // maxAge: userSessionCookieMaxAge, - // httpOnly: false, - // secure: true, - // sameSite: "None", - // domain: c.var.env.COOKIES_DOMAIN, - // path: "/", - // } - // }) - // ) - - throw new Exception({ - statusCode: 401, - internalMessage: "Auth error", - rawError: error, - }) - } -}) +import { AuthEnv } from "../factories/authFactory.js" +import { parseCookies } from "../utilities/cookies/parseCookies.js" +import { unsignString } from "../utilities/cookies/unsignString.js" +import { Exception } from "../utilities/exception.js" +import { selectOne } from "../utilities/sql/selectOne.js" +import { cookiePrefix } from "../utilities/variables.js" +import { models } from "@arrhes/application-metadata/models" +import { eq } from "drizzle-orm" +import { createMiddleware } from "hono/factory" + + +export const authMiddleware = createMiddleware(async (c, next) => { + try { + const cookies = parseCookies({ value: c.req.header("Cookie") }) + const idUserSession = unsignString({ + signedValue: cookies[`${cookiePrefix}_${"id_user_session"}`], + secret: c.var.env.COOKIES_KEY, + }) + + if (idUserSession === undefined) { + throw new Exception({ + internalMessage: "Auth error", + cause: "id_user_session not found in signed cookie", + }) + } + + const userSession = await selectOne({ + database: c.var.clients.sql, + table: models.userSession, + where: (table) => ( + eq(table.id, idUserSession) + ) + }) + if (userSession.isActive === false) { + throw new Exception({ + internalMessage: "Auth error", + cause: "userSession.isActive is false" + }) + } + c.set("userSession", userSession) + + + const user = await selectOne({ + database: c.var.clients.sql, + table: models.user, + where: (table) => ( + eq(table.id, userSession.idUser) + ) + }) + c.set("user", user) + + await next() + } + catch (error: unknown) { + + // const cookieSecurity = getCookieSecurityOptions(c.var.env.ENV) + // c.res.headers.append( + // "Set-Cookie", + // serializeCookie({ + // name: `${cookiePrefix}_${"id_user_session"}`, + // value: "", + // options: { + // maxAge: userSessionCookieMaxAge, + // httpOnly: true, + // ...cookieSecurity, + // domain: c.var.env.COOKIES_DOMAIN, + // path: "/", + // } + // }) + // ) + // c.res.headers.append( + // "Set-Cookie", + // serializeCookie({ + // name: `${cookiePrefix}_${"is_auth"}`, + // value: String(false), + // options: { + // maxAge: userSessionCookieMaxAge, + // httpOnly: false, + // ...cookieSecurity, + // domain: c.var.env.COOKIES_DOMAIN, + // path: "/", + // } + // }) + // ) + + throw new Exception({ + statusCode: 401, + internalMessage: "Auth error", + rawError: error, + }) + } +}) diff --git a/packages/api/src/middlewares/publicMiddleware.ts b/packages/api/src/middlewares/publicMiddleware.ts index 19b5ad8..8b5af9a 100644 --- a/packages/api/src/middlewares/publicMiddleware.ts +++ b/packages/api/src/middlewares/publicMiddleware.ts @@ -1,6 +1,6 @@ -import { publicFactory } from "#/factories/publicFactory.js" - - -export const publicMiddleware = publicFactory.createMiddleware(async (c, next) => { - await next() +import { publicFactory } from "../factories/publicFactory.js" + + +export const publicMiddleware = publicFactory.createMiddleware(async (c, next) => { + await next() }) \ No newline at end of file diff --git a/packages/api/src/middlewares/userVerificationMiddleware.ts b/packages/api/src/middlewares/userVerificationMiddleware.ts index 5c926c2..b211872 100644 --- a/packages/api/src/middlewares/userVerificationMiddleware.ts +++ b/packages/api/src/middlewares/userVerificationMiddleware.ts @@ -1,16 +1,16 @@ -import { authFactory } from "#/factories/authFactory.js" - - -export const userVerificationMiddleware = authFactory.createMiddleware(async (c, next) => { - - // if (c.var.userSession.isUserVerified === false) { - // throw new Exception({ - // statusCode: 403, - // errorCode: "USER_NOT_VERIFIED", - // message: "You must be verified", - // cause: "User is not verified" - // }) - // } - - await next() -}) +import { authFactory } from "../factories/authFactory.js" + + +export const userVerificationMiddleware = authFactory.createMiddleware(async (c, next) => { + + // if (c.var.userSession.isUserVerified === false) { + // throw new Exception({ + // statusCode: 403, + // errorCode: "USER_NOT_VERIFIED", + // message: "You must be verified", + // cause: "User is not verified" + // }) + // } + + await next() +}) diff --git a/packages/api/src/routes/auth/authRoute.ts b/packages/api/src/routes/auth/authRoute.ts index 69e6c67..a811098 100644 --- a/packages/api/src/routes/auth/authRoute.ts +++ b/packages/api/src/routes/auth/authRoute.ts @@ -1,21 +1,21 @@ -import { authFactory } from "#/factories/authFactory.js" -import { authMiddleware } from "#/middlewares/authMiddleware.js" -import { organizationsRoutes } from "#/routes/auth/organizations/organizationsRoutes.js" -import { settingsRoutes } from "#/routes/auth/settings/settingsRoutes.js" -import { supportRoutes } from "#/routes/auth/support/supportRoutes.js" -import { routePath } from "@arrhes/metadata/components" - - -export const authRoute = authFactory.createApp() - .use(`${routePath.auth}/*`, authMiddleware) - - -export const authRoutes = [ - ...organizationsRoutes, - ...settingsRoutes, - ...supportRoutes, -] - -for (const route of authRoutes) { - authRoute.route("/", route) +import { authFactory } from "../../factories/authFactory.js" +import { authMiddleware } from "../../middlewares/authMiddleware.js" +import { organizationsRoutes } from "../../routes/auth/organizations/organizationsRoutes.js" +import { settingsRoutes } from "../../routes/auth/settings/settingsRoutes.js" +import { supportRoutes } from "../../routes/auth/support/supportRoutes.js" +import { routePath } from "@arrhes/application-metadata/components" + + +export const authRoute = authFactory.createApp() + .use(`${routePath.auth}/*`, authMiddleware) + + +export const authRoutes = [ + ...organizationsRoutes, + ...settingsRoutes, + ...supportRoutes, +] + +for (const route of authRoutes) { + authRoute.route("/", route) } \ No newline at end of file diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/$idOrganizationRoutes.ts b/packages/api/src/routes/auth/organizations/$idOrganization/$idOrganizationRoutes.ts index 1699017..042232b 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/$idOrganizationRoutes.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/$idOrganizationRoutes.ts @@ -1,11 +1,11 @@ -import { organizationSettingsRoutes } from "#/routes/auth/organizations/$idOrganization/organizationSettings/organizationSettingsRoutes.js" -import { readOneOrganizationRoute } from "#/routes/auth/organizations/$idOrganization/readOneOrganization.js" -import { yearsRoutes } from "#/routes/auth/organizations/$idOrganization/years/yearsRoutes.js" - - -export const $idOrganizationRoutes = [ - readOneOrganizationRoute, - - ...organizationSettingsRoutes, - ...yearsRoutes, -] +import { organizationSettingsRoutes } from "../../../../routes/auth/organizations/$idOrganization/organizationSettings/organizationSettingsRoutes.js" +import { readOneOrganizationRoute } from "../../../../routes/auth/organizations/$idOrganization/readOneOrganization.js" +import { yearsRoutes } from "../../../../routes/auth/organizations/$idOrganization/years/yearsRoutes.js" + + +export const $idOrganizationRoutes = [ + readOneOrganizationRoute, + + ...organizationSettingsRoutes, + ...yearsRoutes, +] diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/organizationSettings/general/deleteOneOrganization.ts b/packages/api/src/routes/auth/organizations/$idOrganization/organizationSettings/general/deleteOneOrganization.ts index 990e1af..b00d745 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/organizationSettings/general/deleteOneOrganization.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/organizationSettings/general/deleteOneOrganization.ts @@ -1,11 +1,11 @@ -import { authFactory } from "#/factories/authFactory.js" -import { Exception } from "#/utilities/exception.js" -import { response } from "#/utilities/response.js" -import { deleteOne } from "#/utilities/sql/deleteOne.js" -import { selectOne } from "#/utilities/sql/selectOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { deleteOneOrganizationRouteDefinition } from "@arrhes/metadata/routes" +import { authFactory } from "../../../../../../factories/authFactory.js" +import { Exception } from "../../../../../../utilities/exception.js" +import { response } from "../../../../../../utilities/response.js" +import { deleteOne } from "../../../../../../utilities/sql/deleteOne.js" +import { selectOne } from "../../../../../../utilities/sql/selectOne.js" +import { bodyValidator } from "../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { deleteOneOrganizationRouteDefinition } from "@arrhes/application-metadata/routes" import { and, eq } from "drizzle-orm" diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/organizationSettings/general/generalRoutes.ts b/packages/api/src/routes/auth/organizations/$idOrganization/organizationSettings/general/generalRoutes.ts index c012c67..766d5a3 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/organizationSettings/general/generalRoutes.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/organizationSettings/general/generalRoutes.ts @@ -1,5 +1,5 @@ -import { deleteOneOrganizationRoute } from "#/routes/auth/organizations/$idOrganization/organizationSettings/general/deleteOneOrganization.js" -import { updateOneOrganizationRoute } from "#/routes/auth/organizations/$idOrganization/organizationSettings/general/updateOneOrganization.js" +import { deleteOneOrganizationRoute } from "../../../../../../routes/auth/organizations/$idOrganization/organizationSettings/general/deleteOneOrganization.js" +import { updateOneOrganizationRoute } from "../../../../../../routes/auth/organizations/$idOrganization/organizationSettings/general/updateOneOrganization.js" export const generalRoutes = [ diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/organizationSettings/general/updateOneOrganization.ts b/packages/api/src/routes/auth/organizations/$idOrganization/organizationSettings/general/updateOneOrganization.ts index 52d006b..5941101 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/organizationSettings/general/updateOneOrganization.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/organizationSettings/general/updateOneOrganization.ts @@ -1,11 +1,11 @@ -import { authFactory } from "#/factories/authFactory.js" -import { Exception } from "#/utilities/exception.js" -import { response } from "#/utilities/response.js" -import { selectOne } from "#/utilities/sql/selectOne.js" -import { updateOne } from "#/utilities/sql/updateOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { updateOneOrganizationRouteDefinition } from "@arrhes/metadata/routes" +import { authFactory } from "../../../../../../factories/authFactory.js" +import { Exception } from "../../../../../../utilities/exception.js" +import { response } from "../../../../../../utilities/response.js" +import { selectOne } from "../../../../../../utilities/sql/selectOne.js" +import { updateOne } from "../../../../../../utilities/sql/updateOne.js" +import { bodyValidator } from "../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { updateOneOrganizationRouteDefinition } from "@arrhes/application-metadata/routes" import { and, eq } from "drizzle-orm" diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/organizationSettings/organizationSettingsRoutes.ts b/packages/api/src/routes/auth/organizations/$idOrganization/organizationSettings/organizationSettingsRoutes.ts index 710a2ee..561832d 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/organizationSettings/organizationSettingsRoutes.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/organizationSettings/organizationSettingsRoutes.ts @@ -1,5 +1,5 @@ -import { generalRoutes } from "#/routes/auth/organizations/$idOrganization/organizationSettings/general/generalRoutes.js" -import { organizationUsersRoutes } from "#/routes/auth/organizations/$idOrganization/organizationSettings/organizationUser/organizationUsersRoutes.js" +import { generalRoutes } from "../../../../../routes/auth/organizations/$idOrganization/organizationSettings/general/generalRoutes.js" +import { organizationUsersRoutes } from "../../../../../routes/auth/organizations/$idOrganization/organizationSettings/organizationUser/organizationUsersRoutes.js" export const organizationSettingsRoutes = [ diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/organizationSettings/organizationUser/$idOrganizationUser/$idOrganizationUserRoutes.ts b/packages/api/src/routes/auth/organizations/$idOrganization/organizationSettings/organizationUser/$idOrganizationUser/$idOrganizationUserRoutes.ts index 457c565..c746427 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/organizationSettings/organizationUser/$idOrganizationUser/$idOrganizationUserRoutes.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/organizationSettings/organizationUser/$idOrganizationUser/$idOrganizationUserRoutes.ts @@ -1,6 +1,6 @@ -import { deleteOneOrganizationUserRoute } from "#/routes/auth/organizations/$idOrganization/organizationSettings/organizationUser/$idOrganizationUser/deleteOneOrganizationUser.js" -import { readOneOrganizationUserRoute } from "#/routes/auth/organizations/$idOrganization/organizationSettings/organizationUser/$idOrganizationUser/readOneOrganizationUser.js" -import { updateOneOrganizationUserRoute } from "#/routes/auth/organizations/$idOrganization/organizationSettings/organizationUser/$idOrganizationUser/updateOneOrganizationUser.js" +import { deleteOneOrganizationUserRoute } from "../../../../../../../routes/auth/organizations/$idOrganization/organizationSettings/organizationUser/$idOrganizationUser/deleteOneOrganizationUser.js" +import { readOneOrganizationUserRoute } from "../../../../../../../routes/auth/organizations/$idOrganization/organizationSettings/organizationUser/$idOrganizationUser/readOneOrganizationUser.js" +import { updateOneOrganizationUserRoute } from "../../../../../../../routes/auth/organizations/$idOrganization/organizationSettings/organizationUser/$idOrganizationUser/updateOneOrganizationUser.js" export const $idOrganizationUserRoutes = [ diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/organizationSettings/organizationUser/$idOrganizationUser/deleteOneOrganizationUser.ts b/packages/api/src/routes/auth/organizations/$idOrganization/organizationSettings/organizationUser/$idOrganizationUser/deleteOneOrganizationUser.ts index 835b8f9..76f4388 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/organizationSettings/organizationUser/$idOrganizationUser/deleteOneOrganizationUser.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/organizationSettings/organizationUser/$idOrganizationUser/deleteOneOrganizationUser.ts @@ -1,11 +1,11 @@ -import { authFactory } from "#/factories/authFactory.js" -import { Exception } from "#/utilities/exception.js" -import { response } from "#/utilities/response.js" -import { deleteOne } from "#/utilities/sql/deleteOne.js" -import { selectOne } from "#/utilities/sql/selectOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { deleteOneOrganizationUserRouteDefinition } from "@arrhes/metadata/routes" +import { authFactory } from "../../../../../../../factories/authFactory.js" +import { Exception } from "../../../../../../../utilities/exception.js" +import { response } from "../../../../../../../utilities/response.js" +import { deleteOne } from "../../../../../../../utilities/sql/deleteOne.js" +import { selectOne } from "../../../../../../../utilities/sql/selectOne.js" +import { bodyValidator } from "../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { deleteOneOrganizationUserRouteDefinition } from "@arrhes/application-metadata/routes" import { and, eq } from "drizzle-orm" diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/organizationSettings/organizationUser/$idOrganizationUser/readOneOrganizationUser.ts b/packages/api/src/routes/auth/organizations/$idOrganization/organizationSettings/organizationUser/$idOrganizationUser/readOneOrganizationUser.ts index d7438e0..9d9b1ab 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/organizationSettings/organizationUser/$idOrganizationUser/readOneOrganizationUser.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/organizationSettings/organizationUser/$idOrganizationUser/readOneOrganizationUser.ts @@ -1,10 +1,10 @@ -import { authFactory } from "#/factories/authFactory.js" -import { Exception } from "#/utilities/exception.js" -import { response } from "#/utilities/response.js" -import { selectOne } from "#/utilities/sql/selectOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { readOneOrganizationUserRouteDefinition } from "@arrhes/metadata/routes" +import { authFactory } from "../../../../../../../factories/authFactory.js" +import { Exception } from "../../../../../../../utilities/exception.js" +import { response } from "../../../../../../../utilities/response.js" +import { selectOne } from "../../../../../../../utilities/sql/selectOne.js" +import { bodyValidator } from "../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { readOneOrganizationUserRouteDefinition } from "@arrhes/application-metadata/routes" import { and, eq } from "drizzle-orm" diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/organizationSettings/organizationUser/$idOrganizationUser/updateOneOrganizationUser.ts b/packages/api/src/routes/auth/organizations/$idOrganization/organizationSettings/organizationUser/$idOrganizationUser/updateOneOrganizationUser.ts index 62e64aa..179058b 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/organizationSettings/organizationUser/$idOrganizationUser/updateOneOrganizationUser.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/organizationSettings/organizationUser/$idOrganizationUser/updateOneOrganizationUser.ts @@ -1,11 +1,11 @@ -import { authFactory } from "#/factories/authFactory.js" -import { Exception } from "#/utilities/exception.js" -import { response } from "#/utilities/response.js" -import { selectOne } from "#/utilities/sql/selectOne.js" -import { updateOne } from "#/utilities/sql/updateOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { updateOneOrganizationUserRouteDefinition } from "@arrhes/metadata/routes" +import { authFactory } from "../../../../../../../factories/authFactory.js" +import { Exception } from "../../../../../../../utilities/exception.js" +import { response } from "../../../../../../../utilities/response.js" +import { selectOne } from "../../../../../../../utilities/sql/selectOne.js" +import { updateOne } from "../../../../../../../utilities/sql/updateOne.js" +import { bodyValidator } from "../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { updateOneOrganizationUserRouteDefinition } from "@arrhes/application-metadata/routes" import { and, eq } from "drizzle-orm" diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/organizationSettings/organizationUser/createOneOrganizationUser.ts b/packages/api/src/routes/auth/organizations/$idOrganization/organizationSettings/organizationUser/createOneOrganizationUser.ts index cddddac..22c4721 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/organizationSettings/organizationUser/createOneOrganizationUser.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/organizationSettings/organizationUser/createOneOrganizationUser.ts @@ -1,12 +1,12 @@ -import { authFactory } from "#/factories/authFactory.js" -import { Exception } from "#/utilities/exception.js" -import { response } from "#/utilities/response.js" -import { insertOne } from "#/utilities/sql/insertOne.js" -import { selectOne } from "#/utilities/sql/selectOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { createOneOrganizationUserRouteDefinition } from "@arrhes/metadata/routes" -import { generateId } from "@arrhes/metadata/utilities" +import { authFactory } from "../../../../../../factories/authFactory.js" +import { Exception } from "../../../../../../utilities/exception.js" +import { response } from "../../../../../../utilities/response.js" +import { insertOne } from "../../../../../../utilities/sql/insertOne.js" +import { selectOne } from "../../../../../../utilities/sql/selectOne.js" +import { bodyValidator } from "../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { createOneOrganizationUserRouteDefinition } from "@arrhes/application-metadata/routes" +import { generateId } from "@arrhes/application-metadata/utilities" import { and, eq } from "drizzle-orm" diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/organizationSettings/organizationUser/organizationUsersRoutes.ts b/packages/api/src/routes/auth/organizations/$idOrganization/organizationSettings/organizationUser/organizationUsersRoutes.ts index 4a3cd4a..64b0d5e 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/organizationSettings/organizationUser/organizationUsersRoutes.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/organizationSettings/organizationUser/organizationUsersRoutes.ts @@ -1,6 +1,6 @@ -import { $idOrganizationUserRoutes } from "#/routes/auth/organizations/$idOrganization/organizationSettings/organizationUser/$idOrganizationUser/$idOrganizationUserRoutes.js" -import { createOneOrganizationUserRoute } from "#/routes/auth/organizations/$idOrganization/organizationSettings/organizationUser/createOneOrganizationUser.js" -import { readAllOrganizationUsersRoute } from "#/routes/auth/organizations/$idOrganization/organizationSettings/organizationUser/readAllOrganizationUsers.js" +import { $idOrganizationUserRoutes } from "../../../../../../routes/auth/organizations/$idOrganization/organizationSettings/organizationUser/$idOrganizationUser/$idOrganizationUserRoutes.js" +import { createOneOrganizationUserRoute } from "../../../../../../routes/auth/organizations/$idOrganization/organizationSettings/organizationUser/createOneOrganizationUser.js" +import { readAllOrganizationUsersRoute } from "../../../../../../routes/auth/organizations/$idOrganization/organizationSettings/organizationUser/readAllOrganizationUsers.js" export const organizationUsersRoutes = [ diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/organizationSettings/organizationUser/readAllOrganizationUsers.ts b/packages/api/src/routes/auth/organizations/$idOrganization/organizationSettings/organizationUser/readAllOrganizationUsers.ts index 5a63664..aa43974 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/organizationSettings/organizationUser/readAllOrganizationUsers.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/organizationSettings/organizationUser/readAllOrganizationUsers.ts @@ -1,10 +1,10 @@ -import { authFactory } from "#/factories/authFactory.js" -import { Exception } from "#/utilities/exception.js" -import { response } from "#/utilities/response.js" -import { selectOne } from "#/utilities/sql/selectOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { readAllOrganizationUsersRouteDefinition } from "@arrhes/metadata/routes" +import { authFactory } from "../../../../../../factories/authFactory.js" +import { Exception } from "../../../../../../utilities/exception.js" +import { response } from "../../../../../../utilities/response.js" +import { selectOne } from "../../../../../../utilities/sql/selectOne.js" +import { bodyValidator } from "../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { readAllOrganizationUsersRouteDefinition } from "@arrhes/application-metadata/routes" import { and, eq } from "drizzle-orm" diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/readOneOrganization.ts b/packages/api/src/routes/auth/organizations/$idOrganization/readOneOrganization.ts index 86a615e..aeb8ddb 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/readOneOrganization.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/readOneOrganization.ts @@ -1,9 +1,9 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { selectOne } from "#/utilities/sql/selectOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { readOneOrganizationRouteDefinition } from "@arrhes/metadata/routes" +import { authFactory } from "../../../../factories/authFactory.js" +import { response } from "../../../../utilities/response.js" +import { selectOne } from "../../../../utilities/sql/selectOne.js" +import { bodyValidator } from "../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { readOneOrganizationRouteDefinition } from "@arrhes/application-metadata/routes" import { and, eq } from "drizzle-orm" diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/$idYearRoutes.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/$idYearRoutes.ts index 8ee3e1c..2af011b 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/$idYearRoutes.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/$idYearRoutes.ts @@ -1,8 +1,8 @@ -import { attachmentsRoutes } from "#/routes/auth/organizations/$idOrganization/years/$idYear/attachments/attachmentsRoutes.js" -import { readOneYearRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/readOneYear.js" -import { recordsRoutes } from "#/routes/auth/organizations/$idOrganization/years/$idYear/records/recordsRoutes.js" -import { reportsRoutes } from "#/routes/auth/organizations/$idOrganization/years/$idYear/reports/reportsRoutes.js" -import { yearSettingsRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/yearSettingsRoute.js" +import { attachmentsRoutes } from "../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/attachments/attachmentsRoutes.js" +import { readOneYearRoute } from "../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/readOneYear.js" +import { recordsRoutes } from "../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/records/recordsRoutes.js" +import { reportsRoutes } from "../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/reports/reportsRoutes.js" +import { yearSettingsRoute } from "../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/yearSettingsRoute.js" export const $idYearRoutes = [ diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/attachments/$idAttachment/$idAttachmentRoutes.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/attachments/$idAttachment/$idAttachmentRoutes.ts index bd403ce..b3bb10e 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/attachments/$idAttachment/$idAttachmentRoutes.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/attachments/$idAttachment/$idAttachmentRoutes.ts @@ -1,14 +1,14 @@ -import { deleteOneAttachmentRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/attachments/$idAttachment/deleteOneAttachment.js" -import { generateAttachmentGetSignedUrlRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/attachments/$idAttachment/generateAttachmentGetSignedUrl.js" -import { generateAttachmentPutSignedUrlRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/attachments/$idAttachment/generateAttachmentPutSignedUrl.js" -import { readOneAttachmentRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/attachments/$idAttachment/readOneAttachment.js" -import { updateOneAttachmentRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/attachments/$idAttachment/updateOneAttachment.js" - - -export const $idAttachmentRoutes = [ - deleteOneAttachmentRoute, - generateAttachmentGetSignedUrlRoute, - generateAttachmentPutSignedUrlRoute, - readOneAttachmentRoute, - updateOneAttachmentRoute, -] +import { deleteOneAttachmentRoute } from "../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/attachments/$idAttachment/deleteOneAttachment.js" +import { generateAttachmentGetSignedUrlRoute } from "../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/attachments/$idAttachment/generateAttachmentGetSignedUrl.js" +import { generateAttachmentPutSignedUrlRoute } from "../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/attachments/$idAttachment/generateAttachmentPutSignedUrl.js" +import { readOneAttachmentRoute } from "../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/attachments/$idAttachment/readOneAttachment.js" +import { updateOneAttachmentRoute } from "../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/attachments/$idAttachment/updateOneAttachment.js" + + +export const $idAttachmentRoutes = [ + deleteOneAttachmentRoute, + generateAttachmentGetSignedUrlRoute, + generateAttachmentPutSignedUrlRoute, + readOneAttachmentRoute, + updateOneAttachmentRoute, +] diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/attachments/$idAttachment/deleteOneAttachment.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/attachments/$idAttachment/deleteOneAttachment.ts index b80dac8..b1ab7a0 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/attachments/$idAttachment/deleteOneAttachment.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/attachments/$idAttachment/deleteOneAttachment.ts @@ -1,11 +1,11 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { deleteOne } from "#/utilities/sql/deleteOne.js" -import { selectOne } from "#/utilities/sql/selectOne.js" -import { deleteObject } from "#/utilities/storage/deleteObject.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { deleteOneAttachmentRouteDefinition } from "@arrhes/metadata/routes" +import { authFactory } from "../../../../../../../../factories/authFactory.js" +import { response } from "../../../../../../../../utilities/response.js" +import { deleteOne } from "../../../../../../../../utilities/sql/deleteOne.js" +import { selectOne } from "../../../../../../../../utilities/sql/selectOne.js" +import { deleteObject } from "../../../../../../../../utilities/storage/deleteObject.js" +import { bodyValidator } from "../../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { deleteOneAttachmentRouteDefinition } from "@arrhes/application-metadata/routes" import { and, eq } from "drizzle-orm" diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/attachments/$idAttachment/generateAttachmentGetSignedUrl.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/attachments/$idAttachment/generateAttachmentGetSignedUrl.ts index 55109a0..d605782 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/attachments/$idAttachment/generateAttachmentGetSignedUrl.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/attachments/$idAttachment/generateAttachmentGetSignedUrl.ts @@ -1,11 +1,11 @@ -import { authFactory } from "#/factories/authFactory.js" -import { Exception } from "#/utilities/exception.js" -import { response } from "#/utilities/response.js" -import { selectOne } from "#/utilities/sql/selectOne.js" -import { generateGetSignedUrl } from "#/utilities/storage/generateGetSignedUrl.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { generateAttachmentGetSignedUrlRouteDefinition } from "@arrhes/metadata/routes" +import { authFactory } from "../../../../../../../../factories/authFactory.js" +import { Exception } from "../../../../../../../../utilities/exception.js" +import { response } from "../../../../../../../../utilities/response.js" +import { selectOne } from "../../../../../../../../utilities/sql/selectOne.js" +import { generateGetSignedUrl } from "../../../../../../../../utilities/storage/generateGetSignedUrl.js" +import { bodyValidator } from "../../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { generateAttachmentGetSignedUrlRouteDefinition } from "@arrhes/application-metadata/routes" import { and, eq } from "drizzle-orm" diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/attachments/$idAttachment/generateAttachmentPutSignedUrl.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/attachments/$idAttachment/generateAttachmentPutSignedUrl.ts index 211ba50..9e32826 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/attachments/$idAttachment/generateAttachmentPutSignedUrl.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/attachments/$idAttachment/generateAttachmentPutSignedUrl.ts @@ -1,11 +1,11 @@ -import { authFactory } from "#/factories/authFactory.js" -import { Exception } from "#/utilities/exception.js" -import { response } from "#/utilities/response.js" -import { updateOne } from "#/utilities/sql/updateOne.js" -import { generatePutSignedUrl } from "#/utilities/storage/generatePutSignedUrl.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { generateAttachmentPutSignedUrlRouteDefinition } from "@arrhes/metadata/routes" +import { authFactory } from "../../../../../../../../factories/authFactory.js" +import { Exception } from "../../../../../../../../utilities/exception.js" +import { response } from "../../../../../../../../utilities/response.js" +import { updateOne } from "../../../../../../../../utilities/sql/updateOne.js" +import { generatePutSignedUrl } from "../../../../../../../../utilities/storage/generatePutSignedUrl.js" +import { bodyValidator } from "../../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { generateAttachmentPutSignedUrlRouteDefinition } from "@arrhes/application-metadata/routes" import { and, eq } from "drizzle-orm" diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/attachments/$idAttachment/readOneAttachment.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/attachments/$idAttachment/readOneAttachment.ts index 472ba35..01fff81 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/attachments/$idAttachment/readOneAttachment.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/attachments/$idAttachment/readOneAttachment.ts @@ -1,9 +1,9 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { selectOne } from "#/utilities/sql/selectOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { readOneAttachmentRouteDefinition } from "@arrhes/metadata/routes" +import { authFactory } from "../../../../../../../../factories/authFactory.js" +import { response } from "../../../../../../../../utilities/response.js" +import { selectOne } from "../../../../../../../../utilities/sql/selectOne.js" +import { bodyValidator } from "../../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { readOneAttachmentRouteDefinition } from "@arrhes/application-metadata/routes" import { and, eq } from "drizzle-orm" diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/attachments/$idAttachment/updateOneAttachment.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/attachments/$idAttachment/updateOneAttachment.ts index d8043e9..25aacc9 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/attachments/$idAttachment/updateOneAttachment.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/attachments/$idAttachment/updateOneAttachment.ts @@ -1,9 +1,9 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { updateOne } from "#/utilities/sql/updateOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { updateOneAttachmentRouteDefinition } from "@arrhes/metadata/routes" +import { authFactory } from "../../../../../../../../factories/authFactory.js" +import { response } from "../../../../../../../../utilities/response.js" +import { updateOne } from "../../../../../../../../utilities/sql/updateOne.js" +import { bodyValidator } from "../../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { updateOneAttachmentRouteDefinition } from "@arrhes/application-metadata/routes" import { and, eq } from "drizzle-orm" diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/attachments/attachmentsRoutes.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/attachments/attachmentsRoutes.ts index 0d6ce45..44a3c7d 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/attachments/attachmentsRoutes.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/attachments/attachmentsRoutes.ts @@ -1,11 +1,11 @@ -import { $idAttachmentRoutes } from "#/routes/auth/organizations/$idOrganization/years/$idYear/attachments/$idAttachment/$idAttachmentRoutes.js" -import { createOneAttachmentRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/attachments/createOneAttachment.js" -import { readAllAttachmentsRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/attachments/readAllAttachments.js" - - -export const attachmentsRoutes = [ - createOneAttachmentRoute, - readAllAttachmentsRoute, - - ...$idAttachmentRoutes, +import { $idAttachmentRoutes } from "../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/attachments/$idAttachment/$idAttachmentRoutes.js" +import { createOneAttachmentRoute } from "../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/attachments/createOneAttachment.js" +import { readAllAttachmentsRoute } from "../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/attachments/readAllAttachments.js" + + +export const attachmentsRoutes = [ + createOneAttachmentRoute, + readAllAttachmentsRoute, + + ...$idAttachmentRoutes, ] \ No newline at end of file diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/attachments/createOneAttachment.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/attachments/createOneAttachment.ts index 901b321..d1c2a0a 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/attachments/createOneAttachment.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/attachments/createOneAttachment.ts @@ -1,10 +1,10 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { insertOne } from "#/utilities/sql/insertOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { createOneAttachmentRouteDefinition } from "@arrhes/metadata/routes" -import { generateId } from "@arrhes/metadata/utilities" +import { authFactory } from "../../../../../../../factories/authFactory.js" +import { response } from "../../../../../../../utilities/response.js" +import { insertOne } from "../../../../../../../utilities/sql/insertOne.js" +import { bodyValidator } from "../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { createOneAttachmentRouteDefinition } from "@arrhes/application-metadata/routes" +import { generateId } from "@arrhes/application-metadata/utilities" export const createOneAttachmentRoute = authFactory.createApp() diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/attachments/readAllAttachments.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/attachments/readAllAttachments.ts index d8a9ac2..119e927 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/attachments/readAllAttachments.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/attachments/readAllAttachments.ts @@ -1,9 +1,9 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { selectMany } from "#/utilities/sql/selectMany.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { readAllAttachmentsRouteDefinition } from "@arrhes/metadata/routes" +import { authFactory } from "../../../../../../../factories/authFactory.js" +import { response } from "../../../../../../../utilities/response.js" +import { selectMany } from "../../../../../../../utilities/sql/selectMany.js" +import { bodyValidator } from "../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { readAllAttachmentsRouteDefinition } from "@arrhes/application-metadata/routes" import { and, eq } from "drizzle-orm" diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/readOneYear.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/readOneYear.ts index 6acc63b..d54b780 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/readOneYear.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/readOneYear.ts @@ -1,9 +1,9 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { selectOne } from "#/utilities/sql/selectOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { readOneYearRouteDefinition } from "@arrhes/metadata/routes" +import { authFactory } from "../../../../../../factories/authFactory.js" +import { response } from "../../../../../../utilities/response.js" +import { selectOne } from "../../../../../../utilities/sql/selectOne.js" +import { bodyValidator } from "../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { readOneYearRouteDefinition } from "@arrhes/application-metadata/routes" import { and, eq } from "drizzle-orm" diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/$idRecord/$idRecordRoutes.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/$idRecord/$idRecordRoutes.ts index bce21cb..48a3d41 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/$idRecord/$idRecordRoutes.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/$idRecord/$idRecordRoutes.ts @@ -1,7 +1,7 @@ -import { deleteOneRecordRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/records/$idRecord/deleteOneRecord.js" -import { duplicateOneRecordRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/records/$idRecord/duplicateOneRecord.js" -import { readOneRecordRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/records/$idRecord/readOneRecord.js" -import { updateOneRecordRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/records/$idRecord/updateOneRecord.js" +import { deleteOneRecordRoute } from "../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/records/$idRecord/deleteOneRecord.js" +import { duplicateOneRecordRoute } from "../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/records/$idRecord/duplicateOneRecord.js" +import { readOneRecordRoute } from "../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/records/$idRecord/readOneRecord.js" +import { updateOneRecordRoute } from "../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/records/$idRecord/updateOneRecord.js" export const $idRecordRoutes = [ diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/$idRecord/deleteOneRecord.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/$idRecord/deleteOneRecord.ts index 346e57d..c7ab4c8 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/$idRecord/deleteOneRecord.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/$idRecord/deleteOneRecord.ts @@ -1,9 +1,9 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { deleteOne } from "#/utilities/sql/deleteOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { deleteOneRecordRouteDefinition } from "@arrhes/metadata/routes" +import { authFactory } from "../../../../../../../../factories/authFactory.js" +import { response } from "../../../../../../../../utilities/response.js" +import { deleteOne } from "../../../../../../../../utilities/sql/deleteOne.js" +import { bodyValidator } from "../../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { deleteOneRecordRouteDefinition } from "@arrhes/application-metadata/routes" import { and, eq } from "drizzle-orm" diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/$idRecord/duplicateOneRecord.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/$idRecord/duplicateOneRecord.ts index 6091eeb..d4e2a72 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/$idRecord/duplicateOneRecord.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/$idRecord/duplicateOneRecord.ts @@ -1,13 +1,13 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { insertMany } from "#/utilities/sql/insertMany.js" -import { insertOne } from "#/utilities/sql/insertOne.js" -import { selectMany } from "#/utilities/sql/selectMany.js" -import { selectOne } from "#/utilities/sql/selectOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { duplicateOneRecordRouteDefinition } from "@arrhes/metadata/routes" -import { generateId } from "@arrhes/metadata/utilities" +import { authFactory } from "../../../../../../../../factories/authFactory.js" +import { response } from "../../../../../../../../utilities/response.js" +import { insertMany } from "../../../../../../../../utilities/sql/insertMany.js" +import { insertOne } from "../../../../../../../../utilities/sql/insertOne.js" +import { selectMany } from "../../../../../../../../utilities/sql/selectMany.js" +import { selectOne } from "../../../../../../../../utilities/sql/selectOne.js" +import { bodyValidator } from "../../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { duplicateOneRecordRouteDefinition } from "@arrhes/application-metadata/routes" +import { generateId } from "@arrhes/application-metadata/utilities" import { and, eq } from "drizzle-orm" diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/$idRecord/readOneRecord.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/$idRecord/readOneRecord.ts index 612a481..8e40661 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/$idRecord/readOneRecord.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/$idRecord/readOneRecord.ts @@ -1,9 +1,9 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { selectOne } from "#/utilities/sql/selectOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { readOneRecordRouteDefinition } from "@arrhes/metadata/routes" +import { authFactory } from "../../../../../../../../factories/authFactory.js" +import { response } from "../../../../../../../../utilities/response.js" +import { selectOne } from "../../../../../../../../utilities/sql/selectOne.js" +import { bodyValidator } from "../../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { readOneRecordRouteDefinition } from "@arrhes/application-metadata/routes" import { and, eq } from "drizzle-orm" diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/$idRecord/updateOneRecord.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/$idRecord/updateOneRecord.ts index fe07cd3..946f63e 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/$idRecord/updateOneRecord.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/$idRecord/updateOneRecord.ts @@ -1,9 +1,9 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { updateOne } from "#/utilities/sql/updateOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { updateOneRecordRouteDefinition } from "@arrhes/metadata/routes" +import { authFactory } from "../../../../../../../../factories/authFactory.js" +import { response } from "../../../../../../../../utilities/response.js" +import { updateOne } from "../../../../../../../../utilities/sql/updateOne.js" +import { bodyValidator } from "../../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { updateOneRecordRouteDefinition } from "@arrhes/application-metadata/routes" import { and, eq } from "drizzle-orm" diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/createOneRecord.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/createOneRecord.ts index 0bb1caf..77f7266 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/createOneRecord.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/createOneRecord.ts @@ -1,10 +1,10 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { insertOne } from "#/utilities/sql/insertOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { createOneRecordRouteDefinition } from "@arrhes/metadata/routes" -import { generateId } from "@arrhes/metadata/utilities" +import { authFactory } from "../../../../../../../factories/authFactory.js" +import { response } from "../../../../../../../utilities/response.js" +import { insertOne } from "../../../../../../../utilities/sql/insertOne.js" +import { bodyValidator } from "../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { createOneRecordRouteDefinition } from "@arrhes/application-metadata/routes" +import { generateId } from "@arrhes/application-metadata/utilities" export const createOneRecordRoute = authFactory.createApp() diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/readAllRecords.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/readAllRecords.ts index afd35ac..19c7308 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/readAllRecords.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/readAllRecords.ts @@ -1,9 +1,9 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { selectMany } from "#/utilities/sql/selectMany.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { readAllRecordsRouteDefinition } from "@arrhes/metadata/routes" +import { authFactory } from "../../../../../../../factories/authFactory.js" +import { response } from "../../../../../../../utilities/response.js" +import { selectMany } from "../../../../../../../utilities/sql/selectMany.js" +import { bodyValidator } from "../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { readAllRecordsRouteDefinition } from "@arrhes/application-metadata/routes" import { and, eq } from "drizzle-orm" diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/recordRows/$idRecordRow/$idRecordRowRoutes.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/recordRows/$idRecordRow/$idRecordRowRoutes.ts index 22e497a..f6ace19 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/recordRows/$idRecordRow/$idRecordRowRoutes.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/recordRows/$idRecordRow/$idRecordRowRoutes.ts @@ -1,6 +1,6 @@ -import { deleteOneRecordRowRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/records/recordRows/$idRecordRow/deleteOneRecordRow.js" -import { readOneRecordRowRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/records/recordRows/$idRecordRow/readOneRecordRow.js" -import { updateOneRecordRowRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/records/recordRows/$idRecordRow/updateOneRecordRow.js" +import { deleteOneRecordRowRoute } from "../../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/records/recordRows/$idRecordRow/deleteOneRecordRow.js" +import { readOneRecordRowRoute } from "../../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/records/recordRows/$idRecordRow/readOneRecordRow.js" +import { updateOneRecordRowRoute } from "../../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/records/recordRows/$idRecordRow/updateOneRecordRow.js" export const $idRecordRowRoutes = [ diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/recordRows/$idRecordRow/deleteOneRecordRow.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/recordRows/$idRecordRow/deleteOneRecordRow.ts index 6e68813..5c16623 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/recordRows/$idRecordRow/deleteOneRecordRow.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/recordRows/$idRecordRow/deleteOneRecordRow.ts @@ -1,9 +1,9 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { deleteOne } from "#/utilities/sql/deleteOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { deleteOneRecordRowRouteDefinition } from "@arrhes/metadata/routes" +import { authFactory } from "../../../../../../../../../factories/authFactory.js" +import { response } from "../../../../../../../../../utilities/response.js" +import { deleteOne } from "../../../../../../../../../utilities/sql/deleteOne.js" +import { bodyValidator } from "../../../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { deleteOneRecordRowRouteDefinition } from "@arrhes/application-metadata/routes" import { and, eq } from "drizzle-orm" diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/recordRows/$idRecordRow/readOneRecordRow.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/recordRows/$idRecordRow/readOneRecordRow.ts index ae48e19..71e54c4 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/recordRows/$idRecordRow/readOneRecordRow.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/recordRows/$idRecordRow/readOneRecordRow.ts @@ -1,9 +1,9 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { selectOne } from "#/utilities/sql/selectOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { readOneRecordRowRouteDefinition } from "@arrhes/metadata/routes" +import { authFactory } from "../../../../../../../../../factories/authFactory.js" +import { response } from "../../../../../../../../../utilities/response.js" +import { selectOne } from "../../../../../../../../../utilities/sql/selectOne.js" +import { bodyValidator } from "../../../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { readOneRecordRowRouteDefinition } from "@arrhes/application-metadata/routes" import { and, eq } from "drizzle-orm" diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/recordRows/$idRecordRow/updateOneRecordRow.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/recordRows/$idRecordRow/updateOneRecordRow.ts index e3e9b96..685fbd4 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/recordRows/$idRecordRow/updateOneRecordRow.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/recordRows/$idRecordRow/updateOneRecordRow.ts @@ -1,9 +1,9 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { updateOne } from "#/utilities/sql/updateOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { updateOneRecordRowRouteDefinition } from "@arrhes/metadata/routes" +import { authFactory } from "../../../../../../../../../factories/authFactory.js" +import { response } from "../../../../../../../../../utilities/response.js" +import { updateOne } from "../../../../../../../../../utilities/sql/updateOne.js" +import { bodyValidator } from "../../../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { updateOneRecordRowRouteDefinition } from "@arrhes/application-metadata/routes" import { and, eq } from "drizzle-orm" diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/recordRows/createOneRecordRow.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/recordRows/createOneRecordRow.ts index 9f6ae91..938288d 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/recordRows/createOneRecordRow.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/recordRows/createOneRecordRow.ts @@ -1,11 +1,11 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { insertOne } from "#/utilities/sql/insertOne.js" -import { selectOne } from "#/utilities/sql/selectOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { createOneRecordRowRouteDefinition } from "@arrhes/metadata/routes" -import { generateId } from "@arrhes/metadata/utilities" +import { authFactory } from "../../../../../../../../factories/authFactory.js" +import { response } from "../../../../../../../../utilities/response.js" +import { insertOne } from "../../../../../../../../utilities/sql/insertOne.js" +import { selectOne } from "../../../../../../../../utilities/sql/selectOne.js" +import { bodyValidator } from "../../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { createOneRecordRowRouteDefinition } from "@arrhes/application-metadata/routes" +import { generateId } from "@arrhes/application-metadata/utilities" import { and, eq } from "drizzle-orm" diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/recordRows/readAllRecordRows.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/recordRows/readAllRecordRows.ts index f4c6bea..2df42de 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/recordRows/readAllRecordRows.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/recordRows/readAllRecordRows.ts @@ -1,9 +1,9 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { selectMany } from "#/utilities/sql/selectMany.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { readAllRecordRowsRouteDefinition } from "@arrhes/metadata/routes" +import { authFactory } from "../../../../../../../../factories/authFactory.js" +import { response } from "../../../../../../../../utilities/response.js" +import { selectMany } from "../../../../../../../../utilities/sql/selectMany.js" +import { bodyValidator } from "../../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { readAllRecordRowsRouteDefinition } from "@arrhes/application-metadata/routes" import { and, eq } from "drizzle-orm" diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/recordRows/recordRowsRoutes.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/recordRows/recordRowsRoutes.ts index 42f292e..32d757b 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/recordRows/recordRowsRoutes.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/recordRows/recordRowsRoutes.ts @@ -1,7 +1,7 @@ -import { $idRecordRowRoutes } from "#/routes/auth/organizations/$idOrganization/years/$idYear/records/recordRows/$idRecordRow/$idRecordRowRoutes.js" -import { createOneRecordRowRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/records/recordRows/createOneRecordRow.js" -import { readAllRecordRowsRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/records/recordRows/readAllRecordRows.js" -import { updateManyRecordRowsRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/records/recordRows/updateManyRecordRows.js" +import { $idRecordRowRoutes } from "../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/records/recordRows/$idRecordRow/$idRecordRowRoutes.js" +import { createOneRecordRowRoute } from "../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/records/recordRows/createOneRecordRow.js" +import { readAllRecordRowsRoute } from "../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/records/recordRows/readAllRecordRows.js" +import { updateManyRecordRowsRoute } from "../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/records/recordRows/updateManyRecordRows.js" export const recordRowsRoutes = [ diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/recordRows/updateManyRecordRows.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/recordRows/updateManyRecordRows.ts index cbbf9e2..23cbc70 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/recordRows/updateManyRecordRows.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/recordRows/updateManyRecordRows.ts @@ -1,10 +1,10 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { selectMany } from "#/utilities/sql/selectMany.js" -import { updateOne } from "#/utilities/sql/updateOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { updateManyRecordRowsRouteDefinition } from "@arrhes/metadata/routes" +import { authFactory } from "../../../../../../../../factories/authFactory.js" +import { response } from "../../../../../../../../utilities/response.js" +import { selectMany } from "../../../../../../../../utilities/sql/selectMany.js" +import { updateOne } from "../../../../../../../../utilities/sql/updateOne.js" +import { bodyValidator } from "../../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { updateManyRecordRowsRouteDefinition } from "@arrhes/application-metadata/routes" import { and, eq } from "drizzle-orm" diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/recordsRoutes.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/recordsRoutes.ts index e7a4cc5..8462712 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/recordsRoutes.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/records/recordsRoutes.ts @@ -1,7 +1,7 @@ -import { $idRecordRoutes } from "#/routes/auth/organizations/$idOrganization/years/$idYear/records/$idRecord/$idRecordRoutes.js" -import { createOneRecordRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/records/createOneRecord.js" -import { readAllRecordsRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/records/readAllRecords.js" -import { recordRowsRoutes } from "#/routes/auth/organizations/$idOrganization/years/$idYear/records/recordRows/recordRowsRoutes.js" +import { $idRecordRoutes } from "../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/records/$idRecord/$idRecordRoutes.js" +import { createOneRecordRoute } from "../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/records/createOneRecord.js" +import { readAllRecordsRoute } from "../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/records/readAllRecords.js" +import { recordRowsRoutes } from "../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/records/recordRows/recordRowsRoutes.js" export const recordsRoutes = [ diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/reports/document/$idDocument/$idDocumentRoutes.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/reports/document/$idDocument/$idDocumentRoutes.ts index 9e5ac64..c92489d 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/reports/document/$idDocument/$idDocumentRoutes.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/reports/document/$idDocument/$idDocumentRoutes.ts @@ -1,8 +1,8 @@ -import { generateDocumentGetSignedUrlRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/reports/document/$idDocument/generateDocumentGetSignedUrl.js" -import { readOneDocumentRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/reports/document/$idDocument/readOneDocument.js" - - -export const $idDocumentRoutes = [ - generateDocumentGetSignedUrlRoute, - readOneDocumentRoute, +import { generateDocumentGetSignedUrlRoute } from "../../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/reports/document/$idDocument/generateDocumentGetSignedUrl.js" +import { readOneDocumentRoute } from "../../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/reports/document/$idDocument/readOneDocument.js" + + +export const $idDocumentRoutes = [ + generateDocumentGetSignedUrlRoute, + readOneDocumentRoute, ] \ No newline at end of file diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/reports/document/$idDocument/generateDocumentGetSignedUrl.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/reports/document/$idDocument/generateDocumentGetSignedUrl.ts index 01a2626..c441560 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/reports/document/$idDocument/generateDocumentGetSignedUrl.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/reports/document/$idDocument/generateDocumentGetSignedUrl.ts @@ -1,10 +1,10 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { selectOne } from "#/utilities/sql/selectOne.js" -import { generateGetSignedUrl } from "#/utilities/storage/generateGetSignedUrl.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { generateDocumentGetSignedUrlRouteDefinition } from "@arrhes/metadata/routes" +import { authFactory } from "../../../../../../../../../factories/authFactory.js" +import { response } from "../../../../../../../../../utilities/response.js" +import { selectOne } from "../../../../../../../../../utilities/sql/selectOne.js" +import { generateGetSignedUrl } from "../../../../../../../../../utilities/storage/generateGetSignedUrl.js" +import { bodyValidator } from "../../../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { generateDocumentGetSignedUrlRouteDefinition } from "@arrhes/application-metadata/routes" import { and, eq } from "drizzle-orm" diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/reports/document/$idDocument/readOneDocument.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/reports/document/$idDocument/readOneDocument.ts index 2c5d75a..8fc7080 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/reports/document/$idDocument/readOneDocument.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/reports/document/$idDocument/readOneDocument.ts @@ -1,9 +1,9 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { selectOne } from "#/utilities/sql/selectOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { readOneDocumentRouteDefinition } from "@arrhes/metadata/routes" +import { authFactory } from "../../../../../../../../../factories/authFactory.js" +import { response } from "../../../../../../../../../utilities/response.js" +import { selectOne } from "../../../../../../../../../utilities/sql/selectOne.js" +import { bodyValidator } from "../../../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { readOneDocumentRouteDefinition } from "@arrhes/application-metadata/routes" import { and, eq } from "drizzle-orm" diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/reports/document/documentsRoutes.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/reports/document/documentsRoutes.ts index dc5c2ac..f76d344 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/reports/document/documentsRoutes.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/reports/document/documentsRoutes.ts @@ -1,9 +1,9 @@ -import { $idDocumentRoutes } from "#/routes/auth/organizations/$idOrganization/years/$idYear/reports/document/$idDocument/$idDocumentRoutes.js" -import { readAllDocumentsRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/reports/document/readAllDocuments.js" - - -export const documentsRoutes = [ - readAllDocumentsRoute, - - ...$idDocumentRoutes, +import { $idDocumentRoutes } from "../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/reports/document/$idDocument/$idDocumentRoutes.js" +import { readAllDocumentsRoute } from "../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/reports/document/readAllDocuments.js" + + +export const documentsRoutes = [ + readAllDocumentsRoute, + + ...$idDocumentRoutes, ] \ No newline at end of file diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/reports/document/readAllDocuments.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/reports/document/readAllDocuments.ts index dda12a2..e8c4231 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/reports/document/readAllDocuments.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/reports/document/readAllDocuments.ts @@ -1,9 +1,9 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { selectMany } from "#/utilities/sql/selectMany.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { readAllDocumentsRouteDefinition } from "@arrhes/metadata/routes" +import { authFactory } from "../../../../../../../../factories/authFactory.js" +import { response } from "../../../../../../../../utilities/response.js" +import { selectMany } from "../../../../../../../../utilities/sql/selectMany.js" +import { bodyValidator } from "../../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { readAllDocumentsRouteDefinition } from "@arrhes/application-metadata/routes" import { and, eq } from "drizzle-orm" diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/reports/generateBalanceSheetReportDocument.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/reports/generateBalanceSheetReportDocument.ts index 07f1d06..1442e9c 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/reports/generateBalanceSheetReportDocument.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/reports/generateBalanceSheetReportDocument.ts @@ -1,13 +1,13 @@ -import { authFactory } from "#/factories/authFactory.js" -import { balanceSheetReportTemplate } from "#/utilities/email/templates/balanceSheetReport/balanceSheetReport.js" -import { response } from "#/utilities/response.js" -import { insertOne } from "#/utilities/sql/insertOne.js" -import { selectMany } from "#/utilities/sql/selectMany.js" -import { putObject } from "#/utilities/storage/putObject.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { generateBalanceSheetReportDocumentRouteDefinition } from "@arrhes/metadata/routes" -import { generateId } from "@arrhes/metadata/utilities" +import { authFactory } from "../../../../../../../factories/authFactory.js" +import { balanceSheetReportTemplate } from "../../../../../../../utilities/email/templates/balanceSheetReport/balanceSheetReport.js" +import { response } from "../../../../../../../utilities/response.js" +import { insertOne } from "../../../../../../../utilities/sql/insertOne.js" +import { selectMany } from "../../../../../../../utilities/sql/selectMany.js" +import { putObject } from "../../../../../../../utilities/storage/putObject.js" +import { bodyValidator } from "../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { generateBalanceSheetReportDocumentRouteDefinition } from "@arrhes/application-metadata/routes" +import { generateId } from "@arrhes/application-metadata/utilities" import { and, eq } from "drizzle-orm" import path from "path" import { launch } from "puppeteer" diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/reports/generateIncomeStatementReportDocument.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/reports/generateIncomeStatementReportDocument.ts index 941bd3b..57e9a2b 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/reports/generateIncomeStatementReportDocument.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/reports/generateIncomeStatementReportDocument.ts @@ -1,13 +1,13 @@ -import { authFactory } from "#/factories/authFactory.js" -import { incomeStatementReportTemplate } from "#/utilities/email/templates/incomeStatementReport/incomeStatementReport.js" -import { response } from "#/utilities/response.js" -import { insertOne } from "#/utilities/sql/insertOne.js" -import { selectMany } from "#/utilities/sql/selectMany.js" -import { putObject } from "#/utilities/storage/putObject.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { generateIncomeStatementReportDocumentRouteDefinition } from "@arrhes/metadata/routes" -import { generateId } from "@arrhes/metadata/utilities" +import { authFactory } from "../../../../../../../factories/authFactory.js" +import { incomeStatementReportTemplate } from "../../../../../../../utilities/email/templates/incomeStatementReport/incomeStatementReport.js" +import { response } from "../../../../../../../utilities/response.js" +import { insertOne } from "../../../../../../../utilities/sql/insertOne.js" +import { selectMany } from "../../../../../../../utilities/sql/selectMany.js" +import { putObject } from "../../../../../../../utilities/storage/putObject.js" +import { bodyValidator } from "../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { generateIncomeStatementReportDocumentRouteDefinition } from "@arrhes/application-metadata/routes" +import { generateId } from "@arrhes/application-metadata/utilities" import { and, eq } from "drizzle-orm" import path from "path" import { launch } from "puppeteer" diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/reports/reportsRoutes.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/reports/reportsRoutes.ts index f2d6eaf..a946720 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/reports/reportsRoutes.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/reports/reportsRoutes.ts @@ -1,6 +1,6 @@ -import { documentsRoutes } from "#/routes/auth/organizations/$idOrganization/years/$idYear/reports/document/documentsRoutes.js"; -import { generateBalanceSheetReportDocumentRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/reports/generateBalanceSheetReportDocument.js"; -import { generateIncomeStatementReportDocumentRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/reports/generateIncomeStatementReportDocument.js"; +import { documentsRoutes } from "../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/reports/document/documentsRoutes.js"; +import { generateBalanceSheetReportDocumentRoute } from "../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/reports/generateBalanceSheetReportDocument.js"; +import { generateIncomeStatementReportDocumentRoute } from "../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/reports/generateIncomeStatementReportDocument.js"; export const reportsRoutes = [ diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/accounts/$idAccount/$idAccountRoutes.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/accounts/$idAccount/$idAccountRoutes.ts index 5d964f8..1e1c8e1 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/accounts/$idAccount/$idAccountRoutes.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/accounts/$idAccount/$idAccountRoutes.ts @@ -1,10 +1,10 @@ -import { deleteOneAccountRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/accounts/$idAccount/deleteOneAccount.js" -import { readOneAccountRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/accounts/$idAccount/readOneAccount.js" -import { updateOneAccountRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/accounts/$idAccount/updateOneAccount.js" - - -export const $idAccountRoutes = [ - deleteOneAccountRoute, - readOneAccountRoute, - updateOneAccountRoute, +import { deleteOneAccountRoute } from "../../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/accounts/$idAccount/deleteOneAccount.js" +import { readOneAccountRoute } from "../../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/accounts/$idAccount/readOneAccount.js" +import { updateOneAccountRoute } from "../../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/accounts/$idAccount/updateOneAccount.js" + + +export const $idAccountRoutes = [ + deleteOneAccountRoute, + readOneAccountRoute, + updateOneAccountRoute, ] \ No newline at end of file diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/accounts/$idAccount/deleteOneAccount.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/accounts/$idAccount/deleteOneAccount.ts index fadb9f9..8ab7717 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/accounts/$idAccount/deleteOneAccount.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/accounts/$idAccount/deleteOneAccount.ts @@ -1,36 +1,36 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { deleteOne } from "#/utilities/sql/deleteOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { deleteOneAccountRouteDefinition } from "@arrhes/metadata/routes" -import { and, eq } from "drizzle-orm" - - -export const deleteOneAccountRoute = authFactory.createApp() - .post( - deleteOneAccountRouteDefinition.path, - bodyValidator(deleteOneAccountRouteDefinition.schemas.body), - async (c) => { - const body = c.req.valid("json") - - const deleteOneAccount = await deleteOne({ - database: c.var.clients.sql, - table: models.account, - where: (table) => ( - and( - eq(table.idOrganization, body.idOrganization), - eq(table.idYear, body.idYear), - eq(table.id, body.idAccount), - ) - ) - }) - - return response({ - context: c, - statusCode: 200, - schema: deleteOneAccountRouteDefinition.schemas.return, - data: deleteOneAccount, - }) - } +import { authFactory } from "../../../../../../../../../factories/authFactory.js" +import { response } from "../../../../../../../../../utilities/response.js" +import { deleteOne } from "../../../../../../../../../utilities/sql/deleteOne.js" +import { bodyValidator } from "../../../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { deleteOneAccountRouteDefinition } from "@arrhes/application-metadata/routes" +import { and, eq } from "drizzle-orm" + + +export const deleteOneAccountRoute = authFactory.createApp() + .post( + deleteOneAccountRouteDefinition.path, + bodyValidator(deleteOneAccountRouteDefinition.schemas.body), + async (c) => { + const body = c.req.valid("json") + + const deleteOneAccount = await deleteOne({ + database: c.var.clients.sql, + table: models.account, + where: (table) => ( + and( + eq(table.idOrganization, body.idOrganization), + eq(table.idYear, body.idYear), + eq(table.id, body.idAccount), + ) + ) + }) + + return response({ + context: c, + statusCode: 200, + schema: deleteOneAccountRouteDefinition.schemas.return, + data: deleteOneAccount, + }) + } ) \ No newline at end of file diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/accounts/$idAccount/readOneAccount.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/accounts/$idAccount/readOneAccount.ts index a32f296..263c919 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/accounts/$idAccount/readOneAccount.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/accounts/$idAccount/readOneAccount.ts @@ -1,37 +1,37 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { selectOne } from "#/utilities/sql/selectOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { readOneAccountRouteDefinition } from "@arrhes/metadata/routes" -import { and, eq } from "drizzle-orm" - - -export const readOneAccountRoute = authFactory.createApp() - .post( - readOneAccountRouteDefinition.path, - bodyValidator(readOneAccountRouteDefinition.schemas.body), - async (c) => { - - const body = c.req.valid("json") - - const readOneAccount = await selectOne({ - database: c.var.clients.sql, - table: models.account, - where: (table) => ( - and( - eq(table.idOrganization, body.idOrganization), - eq(table.idYear, body.idYear), - eq(table.id, body.idAccount), - ) - ) - }) - - return response({ - context: c, - statusCode: 200, - schema: readOneAccountRouteDefinition.schemas.return, - data: readOneAccount, - }) - } +import { authFactory } from "../../../../../../../../../factories/authFactory.js" +import { response } from "../../../../../../../../../utilities/response.js" +import { selectOne } from "../../../../../../../../../utilities/sql/selectOne.js" +import { bodyValidator } from "../../../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { readOneAccountRouteDefinition } from "@arrhes/application-metadata/routes" +import { and, eq } from "drizzle-orm" + + +export const readOneAccountRoute = authFactory.createApp() + .post( + readOneAccountRouteDefinition.path, + bodyValidator(readOneAccountRouteDefinition.schemas.body), + async (c) => { + + const body = c.req.valid("json") + + const readOneAccount = await selectOne({ + database: c.var.clients.sql, + table: models.account, + where: (table) => ( + and( + eq(table.idOrganization, body.idOrganization), + eq(table.idYear, body.idYear), + eq(table.id, body.idAccount), + ) + ) + }) + + return response({ + context: c, + statusCode: 200, + schema: readOneAccountRouteDefinition.schemas.return, + data: readOneAccount, + }) + } ) \ No newline at end of file diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/accounts/$idAccount/updateOneAccount.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/accounts/$idAccount/updateOneAccount.ts index b00c060..5d7949d 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/accounts/$idAccount/updateOneAccount.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/accounts/$idAccount/updateOneAccount.ts @@ -1,58 +1,58 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { updateOne } from "#/utilities/sql/updateOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { updateOneAccountRouteDefinition } from "@arrhes/metadata/routes" -import { and, eq } from "drizzle-orm" - - -export const updateOneAccountRoute = authFactory.createApp() - .post( - updateOneAccountRouteDefinition.path, - bodyValidator(updateOneAccountRouteDefinition.schemas.body), - async (c) => { - - const body = c.req.valid("json") - - const updateOneAccount = await updateOne({ - database: c.var.clients.sql, - table: models.account, - data: { - idAccountParent: body.idAccountParent, - - idBalanceSheetAsset: body.idBalanceSheetAsset, - balanceSheetAssetColumn: body.balanceSheetAssetColumn, - balanceSheetAssetFlow: body.balanceSheetAssetFlow, - - idBalanceSheetLiability: body.idBalanceSheetLiability, - balanceSheetLiabilityColumn: body.balanceSheetLiabilityColumn, - balanceSheetLiabilityFlow: body.balanceSheetLiabilityFlow, - - idIncomeStatement: body.idIncomeStatement, - - isClass: body.isClass, - isSelectable: body.isSelectable, - number: body.number, - label: body.label, - type: body.type, - lastUpdatedAt: new Date().toISOString(), - lastUpdatedBy: c.var.user.id, - }, - where: (table) => ( - and( - eq(table.idOrganization, body.idOrganization), - eq(table.idYear, body.idYear), - eq(table.id, body.idAccount), - ) - ) - }) - - return response({ - context: c, - statusCode: 200, - schema: updateOneAccountRouteDefinition.schemas.return, - data: updateOneAccount, - }) - } +import { authFactory } from "../../../../../../../../../factories/authFactory.js" +import { response } from "../../../../../../../../../utilities/response.js" +import { updateOne } from "../../../../../../../../../utilities/sql/updateOne.js" +import { bodyValidator } from "../../../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { updateOneAccountRouteDefinition } from "@arrhes/application-metadata/routes" +import { and, eq } from "drizzle-orm" + + +export const updateOneAccountRoute = authFactory.createApp() + .post( + updateOneAccountRouteDefinition.path, + bodyValidator(updateOneAccountRouteDefinition.schemas.body), + async (c) => { + + const body = c.req.valid("json") + + const updateOneAccount = await updateOne({ + database: c.var.clients.sql, + table: models.account, + data: { + idAccountParent: body.idAccountParent, + + idBalanceSheetAsset: body.idBalanceSheetAsset, + balanceSheetAssetColumn: body.balanceSheetAssetColumn, + balanceSheetAssetFlow: body.balanceSheetAssetFlow, + + idBalanceSheetLiability: body.idBalanceSheetLiability, + balanceSheetLiabilityColumn: body.balanceSheetLiabilityColumn, + balanceSheetLiabilityFlow: body.balanceSheetLiabilityFlow, + + idIncomeStatement: body.idIncomeStatement, + + isClass: body.isClass, + isSelectable: body.isSelectable, + number: body.number, + label: body.label, + type: body.type, + lastUpdatedAt: new Date().toISOString(), + lastUpdatedBy: c.var.user.id, + }, + where: (table) => ( + and( + eq(table.idOrganization, body.idOrganization), + eq(table.idYear, body.idYear), + eq(table.id, body.idAccount), + ) + ) + }) + + return response({ + context: c, + statusCode: 200, + schema: updateOneAccountRouteDefinition.schemas.return, + data: updateOneAccount, + }) + } ) \ No newline at end of file diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/accounts/accountsRoutes.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/accounts/accountsRoutes.ts index 92b504e..4bd060a 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/accounts/accountsRoutes.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/accounts/accountsRoutes.ts @@ -1,13 +1,13 @@ -import { $idAccountRoutes } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/accounts/$idAccount/$idAccountRoutes.js" -import { createOneAccountRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/accounts/createOneAccount.js" -import { generateAccountsRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/accounts/generateAccounts.js" -import { readAllAccountsRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/accounts/readAllAccounts.js" - - -export const accountsRoutes = [ - createOneAccountRoute, - readAllAccountsRoute, - generateAccountsRoute, - - ...$idAccountRoutes, +import { $idAccountRoutes } from "../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/accounts/$idAccount/$idAccountRoutes.js" +import { createOneAccountRoute } from "../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/accounts/createOneAccount.js" +import { generateAccountsRoute } from "../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/accounts/generateAccounts.js" +import { readAllAccountsRoute } from "../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/accounts/readAllAccounts.js" + + +export const accountsRoutes = [ + createOneAccountRoute, + readAllAccountsRoute, + generateAccountsRoute, + + ...$idAccountRoutes, ] \ No newline at end of file diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/accounts/createOneAccount.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/accounts/createOneAccount.ts index 827d6fb..3db96dd 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/accounts/createOneAccount.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/accounts/createOneAccount.ts @@ -1,76 +1,76 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { insertOne } from "#/utilities/sql/insertOne.js" -import { selectOne } from "#/utilities/sql/selectOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { createOneAccountRouteDefinition } from "@arrhes/metadata/routes" -import { generateId } from "@arrhes/metadata/utilities" -import { and, eq } from "drizzle-orm" - - -export const createOneAccountRoute = authFactory.createApp() - .post( - createOneAccountRouteDefinition.path, - bodyValidator(createOneAccountRouteDefinition.schemas.body), - async (c) => { - const body = c.req.valid("json") - - const readOneAccount = await selectOne({ - database: c.var.clients.sql, - table: models.account, - where: (table) => { - if (body.idAccountParent === null) { - return - } - return ( - and( - eq(table.idOrganization, body.idOrganization), - eq(table.idYear, body.idYear), - eq(table.id, body.idAccountParent), - ) - ) - } - }) - - const createOneAccount = await insertOne({ - database: c.var.clients.sql, - table: models.account, - data: { - id: generateId(), - idOrganization: body.idOrganization, - idYear: body.idYear, - idAccountParent: body.idAccountParent, - - idBalanceSheetAsset: body.idBalanceSheetAsset ?? readOneAccount?.idBalanceSheetAsset, - balanceSheetAssetColumn: body.balanceSheetAssetColumn ?? readOneAccount?.balanceSheetAssetColumn, - balanceSheetAssetFlow: body.balanceSheetAssetFlow ?? readOneAccount?.balanceSheetAssetFlow, - - idBalanceSheetLiability: body.idBalanceSheetLiability ?? readOneAccount?.idBalanceSheetLiability, - balanceSheetLiabilityColumn: body.balanceSheetLiabilityColumn ?? readOneAccount?.balanceSheetLiabilityColumn, - balanceSheetLiabilityFlow: body.balanceSheetLiabilityFlow ?? readOneAccount?.balanceSheetLiabilityFlow, - - idIncomeStatement: body.idIncomeStatement, - - isClass: body.isClass, - isSelectable: body.isSelectable, - isDefault: false, - label: body.label, - number: body.number, - type: body.type, - isMandatory: true, - createdAt: new Date().toISOString(), - lastUpdatedAt: null, - createdBy: c.var.user.id, - lastUpdatedBy: null, - } - }) - - return response({ - context: c, - statusCode: 200, - schema: createOneAccountRouteDefinition.schemas.return, - data: createOneAccount, - }) - } +import { authFactory } from "../../../../../../../../factories/authFactory.js" +import { response } from "../../../../../../../../utilities/response.js" +import { insertOne } from "../../../../../../../../utilities/sql/insertOne.js" +import { selectOne } from "../../../../../../../../utilities/sql/selectOne.js" +import { bodyValidator } from "../../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { createOneAccountRouteDefinition } from "@arrhes/application-metadata/routes" +import { generateId } from "@arrhes/application-metadata/utilities" +import { and, eq } from "drizzle-orm" + + +export const createOneAccountRoute = authFactory.createApp() + .post( + createOneAccountRouteDefinition.path, + bodyValidator(createOneAccountRouteDefinition.schemas.body), + async (c) => { + const body = c.req.valid("json") + + const readOneAccount = await selectOne({ + database: c.var.clients.sql, + table: models.account, + where: (table) => { + if (body.idAccountParent === null) { + return + } + return ( + and( + eq(table.idOrganization, body.idOrganization), + eq(table.idYear, body.idYear), + eq(table.id, body.idAccountParent), + ) + ) + } + }) + + const createOneAccount = await insertOne({ + database: c.var.clients.sql, + table: models.account, + data: { + id: generateId(), + idOrganization: body.idOrganization, + idYear: body.idYear, + idAccountParent: body.idAccountParent, + + idBalanceSheetAsset: body.idBalanceSheetAsset ?? readOneAccount?.idBalanceSheetAsset, + balanceSheetAssetColumn: body.balanceSheetAssetColumn ?? readOneAccount?.balanceSheetAssetColumn, + balanceSheetAssetFlow: body.balanceSheetAssetFlow ?? readOneAccount?.balanceSheetAssetFlow, + + idBalanceSheetLiability: body.idBalanceSheetLiability ?? readOneAccount?.idBalanceSheetLiability, + balanceSheetLiabilityColumn: body.balanceSheetLiabilityColumn ?? readOneAccount?.balanceSheetLiabilityColumn, + balanceSheetLiabilityFlow: body.balanceSheetLiabilityFlow ?? readOneAccount?.balanceSheetLiabilityFlow, + + idIncomeStatement: body.idIncomeStatement, + + isClass: body.isClass, + isSelectable: body.isSelectable, + isDefault: false, + label: body.label, + number: body.number, + type: body.type, + isMandatory: true, + createdAt: new Date().toISOString(), + lastUpdatedAt: null, + createdBy: c.var.user.id, + lastUpdatedBy: null, + } + }) + + return response({ + context: c, + statusCode: 200, + schema: createOneAccountRouteDefinition.schemas.return, + data: createOneAccount, + }) + } ) \ No newline at end of file diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/accounts/generateAccounts.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/accounts/generateAccounts.ts index 90d610d..16b8ee3 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/accounts/generateAccounts.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/accounts/generateAccounts.ts @@ -1,142 +1,142 @@ -import { authFactory } from "#/factories/authFactory.js" -import { Exception } from "#/utilities/exception.js" -import { response } from "#/utilities/response.js" -import { deleteMany } from "#/utilities/sql/deleteMany.js" -import { insertMany } from "#/utilities/sql/insertMany.js" -import { selectOne } from "#/utilities/sql/selectOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { DefaultAccount, defaultAssociationAccounts, defaultCompanyAccounts } from "@arrhes/metadata/components" -import { models } from "@arrhes/metadata/models" -import { generateAccountsRouteDefinition } from "@arrhes/metadata/routes" -import { returnedSchemas } from "@arrhes/metadata/schemas" -import { generateId } from "@arrhes/metadata/utilities" -import { and, eq } from "drizzle-orm" -import * as v from "valibot" - - -function generateAccounts(parameters: { - accounts: Array - idOrganization: v.InferOutput["id"] - idYear: v.InferOutput["id"] - idAccountParent: v.InferOutput["idAccountParent"] | null -}) { - const newAccounts: Array> = [] - - parameters.accounts.forEach((account) => { - const newAccount = { - id: generateId(), - idOrganization: parameters.idOrganization, - idYear: parameters.idYear, - idAccountParent: parameters.idAccountParent, - - idBalanceSheetAsset: null, - balanceSheetAssetColumn: null, - balanceSheetAssetFlow: null, - - idBalanceSheetLiability: null, - balanceSheetLiabilityColumn: null, - balanceSheetLiabilityFlow: null, - - idIncomeStatement: null, - - number: account.number.toString(), - isMandatory: account.isMandatory, - isClass: account.isClass, - isDefault: true, - isSelectable: account.isSelectable, - label: account.label, - type: account.type, - createdAt: new Date().toISOString(), - lastUpdatedAt: null, - createdBy: null, - lastUpdatedBy: null, - } - newAccounts.push(newAccount) - newAccounts.push(...generateAccounts({ - ...parameters, - accounts: account.children, - idAccountParent: newAccount.id - })) - }) - - return newAccounts -} - - -export const generateAccountsRoute = authFactory.createApp() - .post( - generateAccountsRouteDefinition.path, - bodyValidator(generateAccountsRouteDefinition.schemas.body), - async (c) => { - const body = c.req.valid("json") - - if (body.isReplicatingAccounts === true) { - throw new Exception({ - internalMessage: "Replicating accounts is not implemented yet", - externalMessage: "Non implémenté", - }) - } - - const generatedAccounts = await c.var.clients.sql.transaction(async (tx) => { - try { - const deletedAccounts = await deleteMany({ - database: tx, - table: models.account, - where: (table) => ( - and( - eq(table.idOrganization, body.idOrganization), - eq(table.idYear, body.idYear) - ) - ) - }) - } - catch (error: unknown) { - throw new Exception({ - internalMessage: "Failed to delete accounts", - externalMessage: "Échec de la suppression des comptes", - }) - } - - const organization = await selectOne({ - database: tx, - table: models.organization, - where: (table) => ( - eq(table.id, body.idOrganization) - ) - }) - const defaultAccounts = ( - (organization.scope === "association") - ? defaultAssociationAccounts - : defaultCompanyAccounts - ).filter((account) => { - if (account.isMandatory === false) { - if (body.isMinimalSystem === true) return false - } - return true - }) - - let newAccounts = generateAccounts({ - idOrganization: body.idOrganization, - idYear: body.idYear, - accounts: defaultAccounts, - idAccountParent: null, - }) - - const generatedAccounts = await insertMany({ - database: tx, - table: models.account, - data: newAccounts, - }) - - return generatedAccounts - }) - - - return response({ - context: c, - statusCode: 200, - schema: generateAccountsRouteDefinition.schemas.return, - data: generatedAccounts, - }) - } +import { authFactory } from "../../../../../../../../factories/authFactory.js" +import { Exception } from "../../../../../../../../utilities/exception.js" +import { response } from "../../../../../../../../utilities/response.js" +import { deleteMany } from "../../../../../../../../utilities/sql/deleteMany.js" +import { insertMany } from "../../../../../../../../utilities/sql/insertMany.js" +import { selectOne } from "../../../../../../../../utilities/sql/selectOne.js" +import { bodyValidator } from "../../../../../../../../validators/bodyValidator.js" +import { DefaultAccount, defaultAssociationAccounts, defaultCompanyAccounts } from "@arrhes/application-metadata/components" +import { models } from "@arrhes/application-metadata/models" +import { generateAccountsRouteDefinition } from "@arrhes/application-metadata/routes" +import { returnedSchemas } from "@arrhes/application-metadata/schemas" +import { generateId } from "@arrhes/application-metadata/utilities" +import { and, eq } from "drizzle-orm" +import * as v from "valibot" + + +function generateAccounts(parameters: { + accounts: Array + idOrganization: v.InferOutput["id"] + idYear: v.InferOutput["id"] + idAccountParent: v.InferOutput["idAccountParent"] | null +}) { + const newAccounts: Array> = [] + + parameters.accounts.forEach((account) => { + const newAccount = { + id: generateId(), + idOrganization: parameters.idOrganization, + idYear: parameters.idYear, + idAccountParent: parameters.idAccountParent, + + idBalanceSheetAsset: null, + balanceSheetAssetColumn: null, + balanceSheetAssetFlow: null, + + idBalanceSheetLiability: null, + balanceSheetLiabilityColumn: null, + balanceSheetLiabilityFlow: null, + + idIncomeStatement: null, + + number: account.number.toString(), + isMandatory: account.isMandatory, + isClass: account.isClass, + isDefault: true, + isSelectable: account.isSelectable, + label: account.label, + type: account.type, + createdAt: new Date().toISOString(), + lastUpdatedAt: null, + createdBy: null, + lastUpdatedBy: null, + } + newAccounts.push(newAccount) + newAccounts.push(...generateAccounts({ + ...parameters, + accounts: account.children, + idAccountParent: newAccount.id + })) + }) + + return newAccounts +} + + +export const generateAccountsRoute = authFactory.createApp() + .post( + generateAccountsRouteDefinition.path, + bodyValidator(generateAccountsRouteDefinition.schemas.body), + async (c) => { + const body = c.req.valid("json") + + if (body.isReplicatingAccounts === true) { + throw new Exception({ + internalMessage: "Replicating accounts is not implemented yet", + externalMessage: "Non implémenté", + }) + } + + const generatedAccounts = await c.var.clients.sql.transaction(async (tx) => { + try { + const deletedAccounts = await deleteMany({ + database: tx, + table: models.account, + where: (table) => ( + and( + eq(table.idOrganization, body.idOrganization), + eq(table.idYear, body.idYear) + ) + ) + }) + } + catch (error: unknown) { + throw new Exception({ + internalMessage: "Failed to delete accounts", + externalMessage: "Échec de la suppression des comptes", + }) + } + + const organization = await selectOne({ + database: tx, + table: models.organization, + where: (table) => ( + eq(table.id, body.idOrganization) + ) + }) + const defaultAccounts = ( + (organization.scope === "association") + ? defaultAssociationAccounts + : defaultCompanyAccounts + ).filter((account) => { + if (account.isMandatory === false) { + if (body.isMinimalSystem === true) return false + } + return true + }) + + let newAccounts = generateAccounts({ + idOrganization: body.idOrganization, + idYear: body.idYear, + accounts: defaultAccounts, + idAccountParent: null, + }) + + const generatedAccounts = await insertMany({ + database: tx, + table: models.account, + data: newAccounts, + }) + + return generatedAccounts + }) + + + return response({ + context: c, + statusCode: 200, + schema: generateAccountsRouteDefinition.schemas.return, + data: generatedAccounts, + }) + } ) \ No newline at end of file diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/accounts/readAllAccounts.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/accounts/readAllAccounts.ts index 43f4278..bd0f60c 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/accounts/readAllAccounts.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/accounts/readAllAccounts.ts @@ -1,35 +1,35 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { selectMany } from "#/utilities/sql/selectMany.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { readAllAccountsRouteDefinition } from "@arrhes/metadata/routes" -import { and, eq } from "drizzle-orm" - - -export const readAllAccountsRoute = authFactory.createApp() - .post( - readAllAccountsRouteDefinition.path, - bodyValidator(readAllAccountsRouteDefinition.schemas.body), - async (c) => { - const body = c.req.valid("json") - - const readAllAccounts = await selectMany({ - database: c.var.clients.sql, - table: models.account, - where: (table) => ( - and( - eq(table.idOrganization, body.idOrganization), - eq(table.idYear, body.idYear), - ) - ) - }) - - return response({ - context: c, - statusCode: 200, - schema: readAllAccountsRouteDefinition.schemas.return, - data: readAllAccounts, - }) - } +import { authFactory } from "../../../../../../../../factories/authFactory.js" +import { response } from "../../../../../../../../utilities/response.js" +import { selectMany } from "../../../../../../../../utilities/sql/selectMany.js" +import { bodyValidator } from "../../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { readAllAccountsRouteDefinition } from "@arrhes/application-metadata/routes" +import { and, eq } from "drizzle-orm" + + +export const readAllAccountsRoute = authFactory.createApp() + .post( + readAllAccountsRouteDefinition.path, + bodyValidator(readAllAccountsRouteDefinition.schemas.body), + async (c) => { + const body = c.req.valid("json") + + const readAllAccounts = await selectMany({ + database: c.var.clients.sql, + table: models.account, + where: (table) => ( + and( + eq(table.idOrganization, body.idOrganization), + eq(table.idYear, body.idYear), + ) + ) + }) + + return response({ + context: c, + statusCode: 200, + schema: readAllAccountsRouteDefinition.schemas.return, + data: readAllAccounts, + }) + } ) \ No newline at end of file diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/balanceSheets/$idBalanceSheet/$idBalanceSheetRoutes.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/balanceSheets/$idBalanceSheet/$idBalanceSheetRoutes.ts index 0a4519c..59962b3 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/balanceSheets/$idBalanceSheet/$idBalanceSheetRoutes.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/balanceSheets/$idBalanceSheet/$idBalanceSheetRoutes.ts @@ -1,6 +1,6 @@ -import { deleteOneBalanceSheetRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/balanceSheets/$idBalanceSheet/deleteOneBalanceSheet.js" -import { readOneBalanceSheetRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/balanceSheets/$idBalanceSheet/readOneBalanceSheet.js" -import { updateOneBalanceSheetRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/balanceSheets/$idBalanceSheet/updateOneBalanceSheet.js" +import { deleteOneBalanceSheetRoute } from "../../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/balanceSheets/$idBalanceSheet/deleteOneBalanceSheet.js" +import { readOneBalanceSheetRoute } from "../../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/balanceSheets/$idBalanceSheet/readOneBalanceSheet.js" +import { updateOneBalanceSheetRoute } from "../../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/balanceSheets/$idBalanceSheet/updateOneBalanceSheet.js" export const $idBalanceSheetRoutes = [ diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/balanceSheets/$idBalanceSheet/deleteOneBalanceSheet.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/balanceSheets/$idBalanceSheet/deleteOneBalanceSheet.ts index ded487a..cd31f71 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/balanceSheets/$idBalanceSheet/deleteOneBalanceSheet.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/balanceSheets/$idBalanceSheet/deleteOneBalanceSheet.ts @@ -1,9 +1,9 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { deleteOne } from "#/utilities/sql/deleteOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { deleteOneBalanceSheetRouteDefinition } from "@arrhes/metadata/routes" +import { authFactory } from "../../../../../../../../../factories/authFactory.js" +import { response } from "../../../../../../../../../utilities/response.js" +import { deleteOne } from "../../../../../../../../../utilities/sql/deleteOne.js" +import { bodyValidator } from "../../../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { deleteOneBalanceSheetRouteDefinition } from "@arrhes/application-metadata/routes" import { and, eq } from "drizzle-orm" diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/balanceSheets/$idBalanceSheet/readOneBalanceSheet.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/balanceSheets/$idBalanceSheet/readOneBalanceSheet.ts index 1dedefc..b01bf5f 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/balanceSheets/$idBalanceSheet/readOneBalanceSheet.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/balanceSheets/$idBalanceSheet/readOneBalanceSheet.ts @@ -1,9 +1,9 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { selectOne } from "#/utilities/sql/selectOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { readOneBalanceSheetRouteDefinition } from "@arrhes/metadata/routes" +import { authFactory } from "../../../../../../../../../factories/authFactory.js" +import { response } from "../../../../../../../../../utilities/response.js" +import { selectOne } from "../../../../../../../../../utilities/sql/selectOne.js" +import { bodyValidator } from "../../../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { readOneBalanceSheetRouteDefinition } from "@arrhes/application-metadata/routes" import { and, eq } from "drizzle-orm" diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/balanceSheets/$idBalanceSheet/updateOneBalanceSheet.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/balanceSheets/$idBalanceSheet/updateOneBalanceSheet.ts index 589ee51..40bc721 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/balanceSheets/$idBalanceSheet/updateOneBalanceSheet.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/balanceSheets/$idBalanceSheet/updateOneBalanceSheet.ts @@ -1,9 +1,9 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { updateOne } from "#/utilities/sql/updateOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { updateOneBalanceSheetRouteDefinition } from "@arrhes/metadata/routes" +import { authFactory } from "../../../../../../../../../factories/authFactory.js" +import { response } from "../../../../../../../../../utilities/response.js" +import { updateOne } from "../../../../../../../../../utilities/sql/updateOne.js" +import { bodyValidator } from "../../../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { updateOneBalanceSheetRouteDefinition } from "@arrhes/application-metadata/routes" import { and, eq } from "drizzle-orm" diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/balanceSheets/balanceSheetsRoutes.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/balanceSheets/balanceSheetsRoutes.ts index 8d528fb..ee8a3cd 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/balanceSheets/balanceSheetsRoutes.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/balanceSheets/balanceSheetsRoutes.ts @@ -1,8 +1,8 @@ -import { $idBalanceSheetRoutes } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/balanceSheets/$idBalanceSheet/$idBalanceSheetRoutes.js" -import { connectAccountsToBalanceSheetsRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/balanceSheets/connectAccountsToBalanceSheets.js" -import { createOneBalanceSheetRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/balanceSheets/createOneBalanceSheet.js" -import { generateBalanceSheetsRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/balanceSheets/generateBalanceSheets.js" -import { readAllBalanceSheetsRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/balanceSheets/readAllBalanceSheets.js" +import { $idBalanceSheetRoutes } from "../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/balanceSheets/$idBalanceSheet/$idBalanceSheetRoutes.js" +import { connectAccountsToBalanceSheetsRoute } from "../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/balanceSheets/connectAccountsToBalanceSheets.js" +import { createOneBalanceSheetRoute } from "../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/balanceSheets/createOneBalanceSheet.js" +import { generateBalanceSheetsRoute } from "../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/balanceSheets/generateBalanceSheets.js" +import { readAllBalanceSheetsRoute } from "../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/balanceSheets/readAllBalanceSheets.js" export const balanceSheetsRoutes = [ diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/balanceSheets/connectAccountsToBalanceSheets.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/balanceSheets/connectAccountsToBalanceSheets.ts index 582690e..3c47cbe 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/balanceSheets/connectAccountsToBalanceSheets.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/balanceSheets/connectAccountsToBalanceSheets.ts @@ -1,143 +1,143 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { selectMany } from "#/utilities/sql/selectMany.js" -import { selectOne } from "#/utilities/sql/selectOne.js" -import { updateOne } from "#/utilities/sql/updateOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { defaultAssociationBalanceSheets, defaultCompanyBalanceSheets } from "@arrhes/metadata/components" -import { models } from "@arrhes/metadata/models" -import { connectAccountsToBalanceSheetsRouteDefinition } from "@arrhes/metadata/routes" -import { and, eq } from "drizzle-orm" - - -export const connectAccountsToBalanceSheetsRoute = authFactory.createApp() - .post( - connectAccountsToBalanceSheetsRouteDefinition.path, - bodyValidator(connectAccountsToBalanceSheetsRouteDefinition.schemas.body), - async (c) => { - const body = c.req.valid("json") - - const readAllAccounts = await selectMany({ - database: c.var.clients.sql, - table: models.account, - where: (table) => ( - and( - eq(table.idOrganization, body.idOrganization), - eq(table.idYear, body.idYear), - ) - ) - }) - - const readAllBalanceSheets = await selectMany({ - database: c.var.clients.sql, - table: models.balanceSheet, - where: (table) => ( - and( - eq(table.idOrganization, body.idOrganization), - eq(table.idYear, body.idYear), - ) - ) - }) - - const organization = await selectOne({ - database: c.var.clients.sql, - table: models.organization, - where: (table) => ( - eq(table.id, body.idOrganization) - ) - }) - const defaultBalanceSheets = ( - (organization.scope === "association") - ? defaultAssociationBalanceSheets - : defaultCompanyBalanceSheets - ) - - const connectAccountsToBalanceSheets = await c.var.clients.sql.transaction(async (tx) => { - for (const defaultBalanceSheet of defaultBalanceSheets) { - for (const defaultAccount of defaultBalanceSheet.accounts) { - - const foundAccount = readAllAccounts.find((account) => { - return account.number === defaultAccount.number.toString() - }) - - if (foundAccount === undefined) { - console.log("foundAccount is undefined", defaultBalanceSheet.number, defaultAccount) - continue - } - - const balanceSheet = readAllBalanceSheets.find((balanceSheet) => balanceSheet.number === defaultBalanceSheet.number.toString()) - if (balanceSheet === undefined) { - console.log("balanceSheet is undefined", defaultBalanceSheet.number) - continue - } - - const updateOneAccount = await updateOne({ - database: tx, - table: models.account, - data: { - idBalanceSheetAsset: (defaultBalanceSheet.side === "asset") - ? balanceSheet.id - : undefined, - balanceSheetAssetColumn: (defaultBalanceSheet.side === "asset") - ? (defaultAccount.isAmortization) - ? "amortization" - : "gross" - : undefined, - balanceSheetAssetFlow: (defaultBalanceSheet.side === "asset") - ? defaultAccount.flow - : undefined, - - idBalanceSheetLiability: (defaultBalanceSheet.side === "liability") - ? balanceSheet.id - : undefined, - balanceSheetLiabilityColumn: (defaultBalanceSheet.side === "liability") - ? "net" - : undefined, - balanceSheetLiabilityFlow: (defaultBalanceSheet.side === "liability") - ? defaultAccount.flow - : undefined, - - lastUpdatedAt: new Date().toISOString(), - lastUpdatedBy: c.var.user.id, - }, - where: (table) => ( - and( - eq(table.idOrganization, body.idOrganization), - eq(table.idYear, body.idYear), - eq(table.id, foundAccount.id), - ) - ) - }) - } - } - for (const account of readAllAccounts) { - - - const defaultBalanceSheet = defaultBalanceSheets.find((defaultBalanceSheet) => { - const foundAccount = defaultBalanceSheet.accounts.find((defaultAccount) => defaultAccount.number.toString() === account.number) - - return false - }) - - if (defaultBalanceSheet === undefined) { - continue - } - - const balanceSheet = readAllBalanceSheets.find((balanceSheet) => balanceSheet.number === defaultBalanceSheet.number.toString()) - if (balanceSheet === undefined) { - continue - } - - - } - }) - - - return response({ - context: c, - statusCode: 200, - schema: connectAccountsToBalanceSheetsRouteDefinition.schemas.return, - data: {}, - }) - } +import { authFactory } from "../../../../../../../../factories/authFactory.js" +import { response } from "../../../../../../../../utilities/response.js" +import { selectMany } from "../../../../../../../../utilities/sql/selectMany.js" +import { selectOne } from "../../../../../../../../utilities/sql/selectOne.js" +import { updateOne } from "../../../../../../../../utilities/sql/updateOne.js" +import { bodyValidator } from "../../../../../../../../validators/bodyValidator.js" +import { defaultAssociationBalanceSheets, defaultCompanyBalanceSheets } from "@arrhes/application-metadata/components" +import { models } from "@arrhes/application-metadata/models" +import { connectAccountsToBalanceSheetsRouteDefinition } from "@arrhes/application-metadata/routes" +import { and, eq } from "drizzle-orm" + + +export const connectAccountsToBalanceSheetsRoute = authFactory.createApp() + .post( + connectAccountsToBalanceSheetsRouteDefinition.path, + bodyValidator(connectAccountsToBalanceSheetsRouteDefinition.schemas.body), + async (c) => { + const body = c.req.valid("json") + + const readAllAccounts = await selectMany({ + database: c.var.clients.sql, + table: models.account, + where: (table) => ( + and( + eq(table.idOrganization, body.idOrganization), + eq(table.idYear, body.idYear), + ) + ) + }) + + const readAllBalanceSheets = await selectMany({ + database: c.var.clients.sql, + table: models.balanceSheet, + where: (table) => ( + and( + eq(table.idOrganization, body.idOrganization), + eq(table.idYear, body.idYear), + ) + ) + }) + + const organization = await selectOne({ + database: c.var.clients.sql, + table: models.organization, + where: (table) => ( + eq(table.id, body.idOrganization) + ) + }) + const defaultBalanceSheets = ( + (organization.scope === "association") + ? defaultAssociationBalanceSheets + : defaultCompanyBalanceSheets + ) + + const connectAccountsToBalanceSheets = await c.var.clients.sql.transaction(async (tx) => { + for (const defaultBalanceSheet of defaultBalanceSheets) { + for (const defaultAccount of defaultBalanceSheet.accounts) { + + const foundAccount = readAllAccounts.find((account) => { + return account.number === defaultAccount.number.toString() + }) + + if (foundAccount === undefined) { + console.log("foundAccount is undefined", defaultBalanceSheet.number, defaultAccount) + continue + } + + const balanceSheet = readAllBalanceSheets.find((balanceSheet) => balanceSheet.number === defaultBalanceSheet.number.toString()) + if (balanceSheet === undefined) { + console.log("balanceSheet is undefined", defaultBalanceSheet.number) + continue + } + + const updateOneAccount = await updateOne({ + database: tx, + table: models.account, + data: { + idBalanceSheetAsset: (defaultBalanceSheet.side === "asset") + ? balanceSheet.id + : undefined, + balanceSheetAssetColumn: (defaultBalanceSheet.side === "asset") + ? (defaultAccount.isAmortization) + ? "amortization" + : "gross" + : undefined, + balanceSheetAssetFlow: (defaultBalanceSheet.side === "asset") + ? defaultAccount.flow + : undefined, + + idBalanceSheetLiability: (defaultBalanceSheet.side === "liability") + ? balanceSheet.id + : undefined, + balanceSheetLiabilityColumn: (defaultBalanceSheet.side === "liability") + ? "net" + : undefined, + balanceSheetLiabilityFlow: (defaultBalanceSheet.side === "liability") + ? defaultAccount.flow + : undefined, + + lastUpdatedAt: new Date().toISOString(), + lastUpdatedBy: c.var.user.id, + }, + where: (table) => ( + and( + eq(table.idOrganization, body.idOrganization), + eq(table.idYear, body.idYear), + eq(table.id, foundAccount.id), + ) + ) + }) + } + } + for (const account of readAllAccounts) { + + + const defaultBalanceSheet = defaultBalanceSheets.find((defaultBalanceSheet) => { + const foundAccount = defaultBalanceSheet.accounts.find((defaultAccount) => defaultAccount.number.toString() === account.number) + + return false + }) + + if (defaultBalanceSheet === undefined) { + continue + } + + const balanceSheet = readAllBalanceSheets.find((balanceSheet) => balanceSheet.number === defaultBalanceSheet.number.toString()) + if (balanceSheet === undefined) { + continue + } + + + } + }) + + + return response({ + context: c, + statusCode: 200, + schema: connectAccountsToBalanceSheetsRouteDefinition.schemas.return, + data: {}, + }) + } ) \ No newline at end of file diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/balanceSheets/createOneBalanceSheet.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/balanceSheets/createOneBalanceSheet.ts index 7a78ea9..fe92cb5 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/balanceSheets/createOneBalanceSheet.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/balanceSheets/createOneBalanceSheet.ts @@ -1,10 +1,10 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { insertOne } from "#/utilities/sql/insertOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { createOneBalanceSheetRouteDefinition } from "@arrhes/metadata/routes" -import { generateId } from "@arrhes/metadata/utilities" +import { authFactory } from "../../../../../../../../factories/authFactory.js" +import { response } from "../../../../../../../../utilities/response.js" +import { insertOne } from "../../../../../../../../utilities/sql/insertOne.js" +import { bodyValidator } from "../../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { createOneBalanceSheetRouteDefinition } from "@arrhes/application-metadata/routes" +import { generateId } from "@arrhes/application-metadata/utilities" export const createOneBalanceSheetRoute = authFactory.createApp() diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/balanceSheets/generateBalanceSheets.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/balanceSheets/generateBalanceSheets.ts index c45f5ec..3fb452b 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/balanceSheets/generateBalanceSheets.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/balanceSheets/generateBalanceSheets.ts @@ -1,104 +1,104 @@ -import { authFactory } from "#/factories/authFactory.js" -import { Exception } from "#/utilities/exception.js" -import { response } from "#/utilities/response.js" -import { deleteMany } from "#/utilities/sql/deleteMany.js" -import { insertMany } from "#/utilities/sql/insertMany.js" -import { selectOne } from "#/utilities/sql/selectOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { defaultAssociationBalanceSheets, defaultCompanyBalanceSheets } from "@arrhes/metadata/components" -import { models } from "@arrhes/metadata/models" -import { generateBalanceSheetsRouteDefinition } from "@arrhes/metadata/routes" -import { returnedSchemas } from "@arrhes/metadata/schemas" -import { generateId } from "@arrhes/metadata/utilities" -import { and, eq } from "drizzle-orm" -import * as v from "valibot" - - -export const generateBalanceSheetsRoute = authFactory.createApp() - .post( - generateBalanceSheetsRouteDefinition.path, - bodyValidator(generateBalanceSheetsRouteDefinition.schemas.body), - async (c) => { - const body = c.req.valid("json") - - const generatedBalanceSheets = await c.var.clients.sql.transaction(async (tx) => { - try { - const deletedBalanceSheets = await deleteMany({ - database: tx, - table: models.balanceSheet, - where: (table) => ( - and( - eq(table.idOrganization, body.idOrganization), - eq(table.idYear, body.idYear) - ) - ) - }) - } - catch (error: unknown) { - throw new Exception({ - internalMessage: "Failed to delete balanceSheets", - externalMessage: "Échec de la suppression des lignes de bilan", - }) - } - - const organization = await selectOne({ - database: tx, - table: models.organization, - where: (table) => ( - eq(table.id, body.idOrganization) - ) - }) - const defaultBalanceSheets = ( - (organization.scope === "association") - ? defaultAssociationBalanceSheets - : defaultCompanyBalanceSheets - ) - - - const newBalanceSheets: Array> = [] - - defaultBalanceSheets - .forEach((defaultBalanceSheet) => { - const balanceSheetParent = newBalanceSheets.find((newBalanceSheet) => { - const isParent = newBalanceSheet.number === defaultBalanceSheet.numberParent?.toString() - const isSameSide = newBalanceSheet.side === defaultBalanceSheet.side - return isParent && isSameSide - }) - newBalanceSheets.push({ - id: generateId(), - idOrganization: body.idOrganization, - idYear: body.idYear, - idBalanceSheetParent: balanceSheetParent?.id ?? null, - number: defaultBalanceSheet.number.toString(), - isDefault: true, - isComputed: (balanceSheetParent === undefined) - ? true - : false, - label: defaultBalanceSheet.label, - side: defaultBalanceSheet.side, - createdAt: new Date().toISOString(), - lastUpdatedAt: null, - createdBy: null, - lastUpdatedBy: null, - }) - }) - - - const generatedBalanceSheets = await insertMany({ - database: tx, - table: models.balanceSheet, - data: newBalanceSheets, - }) - - return generatedBalanceSheets - }) - - - return response({ - context: c, - statusCode: 200, - schema: generateBalanceSheetsRouteDefinition.schemas.return, - data: generatedBalanceSheets, - }) - } +import { authFactory } from "../../../../../../../../factories/authFactory.js" +import { Exception } from "../../../../../../../../utilities/exception.js" +import { response } from "../../../../../../../../utilities/response.js" +import { deleteMany } from "../../../../../../../../utilities/sql/deleteMany.js" +import { insertMany } from "../../../../../../../../utilities/sql/insertMany.js" +import { selectOne } from "../../../../../../../../utilities/sql/selectOne.js" +import { bodyValidator } from "../../../../../../../../validators/bodyValidator.js" +import { defaultAssociationBalanceSheets, defaultCompanyBalanceSheets } from "@arrhes/application-metadata/components" +import { models } from "@arrhes/application-metadata/models" +import { generateBalanceSheetsRouteDefinition } from "@arrhes/application-metadata/routes" +import { returnedSchemas } from "@arrhes/application-metadata/schemas" +import { generateId } from "@arrhes/application-metadata/utilities" +import { and, eq } from "drizzle-orm" +import * as v from "valibot" + + +export const generateBalanceSheetsRoute = authFactory.createApp() + .post( + generateBalanceSheetsRouteDefinition.path, + bodyValidator(generateBalanceSheetsRouteDefinition.schemas.body), + async (c) => { + const body = c.req.valid("json") + + const generatedBalanceSheets = await c.var.clients.sql.transaction(async (tx) => { + try { + const deletedBalanceSheets = await deleteMany({ + database: tx, + table: models.balanceSheet, + where: (table) => ( + and( + eq(table.idOrganization, body.idOrganization), + eq(table.idYear, body.idYear) + ) + ) + }) + } + catch (error: unknown) { + throw new Exception({ + internalMessage: "Failed to delete balanceSheets", + externalMessage: "Échec de la suppression des lignes de bilan", + }) + } + + const organization = await selectOne({ + database: tx, + table: models.organization, + where: (table) => ( + eq(table.id, body.idOrganization) + ) + }) + const defaultBalanceSheets = ( + (organization.scope === "association") + ? defaultAssociationBalanceSheets + : defaultCompanyBalanceSheets + ) + + + const newBalanceSheets: Array> = [] + + defaultBalanceSheets + .forEach((defaultBalanceSheet) => { + const balanceSheetParent = newBalanceSheets.find((newBalanceSheet) => { + const isParent = newBalanceSheet.number === defaultBalanceSheet.numberParent?.toString() + const isSameSide = newBalanceSheet.side === defaultBalanceSheet.side + return isParent && isSameSide + }) + newBalanceSheets.push({ + id: generateId(), + idOrganization: body.idOrganization, + idYear: body.idYear, + idBalanceSheetParent: balanceSheetParent?.id ?? null, + number: defaultBalanceSheet.number.toString(), + isDefault: true, + isComputed: (balanceSheetParent === undefined) + ? true + : false, + label: defaultBalanceSheet.label, + side: defaultBalanceSheet.side, + createdAt: new Date().toISOString(), + lastUpdatedAt: null, + createdBy: null, + lastUpdatedBy: null, + }) + }) + + + const generatedBalanceSheets = await insertMany({ + database: tx, + table: models.balanceSheet, + data: newBalanceSheets, + }) + + return generatedBalanceSheets + }) + + + return response({ + context: c, + statusCode: 200, + schema: generateBalanceSheetsRouteDefinition.schemas.return, + data: generatedBalanceSheets, + }) + } ) \ No newline at end of file diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/balanceSheets/readAllBalanceSheets.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/balanceSheets/readAllBalanceSheets.ts index 1b16e96..b677153 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/balanceSheets/readAllBalanceSheets.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/balanceSheets/readAllBalanceSheets.ts @@ -1,9 +1,9 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { selectMany } from "#/utilities/sql/selectMany.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { readAllBalanceSheetsRouteDefinition } from "@arrhes/metadata/routes" +import { authFactory } from "../../../../../../../../factories/authFactory.js" +import { response } from "../../../../../../../../utilities/response.js" +import { selectMany } from "../../../../../../../../utilities/sql/selectMany.js" +import { bodyValidator } from "../../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { readAllBalanceSheetsRouteDefinition } from "@arrhes/application-metadata/routes" import { and, eq } from "drizzle-orm" diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/$idComputationRoutes.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/$idComputationRoutes.ts index 8374c4a..aa6258a 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/$idComputationRoutes.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/$idComputationRoutes.ts @@ -1,13 +1,13 @@ -import { computationIncomeStatementsRoutes } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/computationIncomeStatements/computationIncomeStatementsRoutes.js" -import { deleteOneComputationRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/deleteOneComputation.js" -import { readOneComputationRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/readOneComputation.js" -import { updateOneComputationRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/updateOneComputation.js" - - -export const $idComputationRoutes = [ - deleteOneComputationRoute, - readOneComputationRoute, - updateOneComputationRoute, - - ...computationIncomeStatementsRoutes, -] +import { computationIncomeStatementsRoutes } from "../../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/computationIncomeStatements/computationIncomeStatementsRoutes.js" +import { deleteOneComputationRoute } from "../../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/deleteOneComputation.js" +import { readOneComputationRoute } from "../../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/readOneComputation.js" +import { updateOneComputationRoute } from "../../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/updateOneComputation.js" + + +export const $idComputationRoutes = [ + deleteOneComputationRoute, + readOneComputationRoute, + updateOneComputationRoute, + + ...computationIncomeStatementsRoutes, +] diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/computationIncomeStatements/$idComputationIncomeStatement/$idComputationIncomeStatementRoutes.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/computationIncomeStatements/$idComputationIncomeStatement/$idComputationIncomeStatementRoutes.ts index 20c11c2..37d05a1 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/computationIncomeStatements/$idComputationIncomeStatement/$idComputationIncomeStatementRoutes.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/computationIncomeStatements/$idComputationIncomeStatement/$idComputationIncomeStatementRoutes.ts @@ -1,10 +1,10 @@ -import { deleteOneComputationIncomeStatementRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/computationIncomeStatements/$idComputationIncomeStatement/deleteOneComputationIncomeStatement.js" -import { readOneComputationIncomeStatementRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/computationIncomeStatements/$idComputationIncomeStatement/readOneComputationIncomeStatement.js" -import { updateOneComputationIncomeStatementRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/computationIncomeStatements/$idComputationIncomeStatement/updateOneComputationIncomeStatement.js" - - -export const $idComputationIncomeStatementRoutes = [ - deleteOneComputationIncomeStatementRoute, - readOneComputationIncomeStatementRoute, - updateOneComputationIncomeStatementRoute, -] +import { deleteOneComputationIncomeStatementRoute } from "../../../../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/computationIncomeStatements/$idComputationIncomeStatement/deleteOneComputationIncomeStatement.js" +import { readOneComputationIncomeStatementRoute } from "../../../../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/computationIncomeStatements/$idComputationIncomeStatement/readOneComputationIncomeStatement.js" +import { updateOneComputationIncomeStatementRoute } from "../../../../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/computationIncomeStatements/$idComputationIncomeStatement/updateOneComputationIncomeStatement.js" + + +export const $idComputationIncomeStatementRoutes = [ + deleteOneComputationIncomeStatementRoute, + readOneComputationIncomeStatementRoute, + updateOneComputationIncomeStatementRoute, +] diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/computationIncomeStatements/$idComputationIncomeStatement/deleteOneComputationIncomeStatement.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/computationIncomeStatements/$idComputationIncomeStatement/deleteOneComputationIncomeStatement.ts index a0ed421..34e2d37 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/computationIncomeStatements/$idComputationIncomeStatement/deleteOneComputationIncomeStatement.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/computationIncomeStatements/$idComputationIncomeStatement/deleteOneComputationIncomeStatement.ts @@ -1,9 +1,9 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { deleteOne } from "#/utilities/sql/deleteOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { deleteOneComputationIncomeStatementRouteDefinition } from "@arrhes/metadata/routes" +import { authFactory } from "../../../../../../../../../../../factories/authFactory.js" +import { response } from "../../../../../../../../../../../utilities/response.js" +import { deleteOne } from "../../../../../../../../../../../utilities/sql/deleteOne.js" +import { bodyValidator } from "../../../../../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { deleteOneComputationIncomeStatementRouteDefinition } from "@arrhes/application-metadata/routes" import { and, eq } from "drizzle-orm" diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/computationIncomeStatements/$idComputationIncomeStatement/readOneComputationIncomeStatement.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/computationIncomeStatements/$idComputationIncomeStatement/readOneComputationIncomeStatement.ts index 073f72f..189d8f0 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/computationIncomeStatements/$idComputationIncomeStatement/readOneComputationIncomeStatement.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/computationIncomeStatements/$idComputationIncomeStatement/readOneComputationIncomeStatement.ts @@ -1,9 +1,9 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { selectOne } from "#/utilities/sql/selectOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { readOneComputationIncomeStatementRouteDefinition } from "@arrhes/metadata/routes" +import { authFactory } from "../../../../../../../../../../../factories/authFactory.js" +import { response } from "../../../../../../../../../../../utilities/response.js" +import { selectOne } from "../../../../../../../../../../../utilities/sql/selectOne.js" +import { bodyValidator } from "../../../../../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { readOneComputationIncomeStatementRouteDefinition } from "@arrhes/application-metadata/routes" import { and, eq } from "drizzle-orm" diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/computationIncomeStatements/$idComputationIncomeStatement/updateOneComputationIncomeStatement.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/computationIncomeStatements/$idComputationIncomeStatement/updateOneComputationIncomeStatement.ts index f182ff5..f8feecd 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/computationIncomeStatements/$idComputationIncomeStatement/updateOneComputationIncomeStatement.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/computationIncomeStatements/$idComputationIncomeStatement/updateOneComputationIncomeStatement.ts @@ -1,9 +1,9 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { updateOne } from "#/utilities/sql/updateOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { updateOneComputationIncomeStatementRouteDefinition } from "@arrhes/metadata/routes" +import { authFactory } from "../../../../../../../../../../../factories/authFactory.js" +import { response } from "../../../../../../../../../../../utilities/response.js" +import { updateOne } from "../../../../../../../../../../../utilities/sql/updateOne.js" +import { bodyValidator } from "../../../../../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { updateOneComputationIncomeStatementRouteDefinition } from "@arrhes/application-metadata/routes" import { and, eq } from "drizzle-orm" diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/computationIncomeStatements/computationIncomeStatementsRoutes.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/computationIncomeStatements/computationIncomeStatementsRoutes.ts index b1ed488..ef5cf41 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/computationIncomeStatements/computationIncomeStatementsRoutes.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/computationIncomeStatements/computationIncomeStatementsRoutes.ts @@ -1,12 +1,12 @@ -import { $idComputationIncomeStatementRoutes } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/computationIncomeStatements/$idComputationIncomeStatement/$idComputationIncomeStatementRoutes.js" -import { createOneComputationIncomeStatementRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/computationIncomeStatements/createOneComputationIncomeStatement.js" -import { readAllComputationIncomeStatementsRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/computationIncomeStatements/readAllComputationIncomeStatements.js" - - -export const computationIncomeStatementsRoutes = [ - createOneComputationIncomeStatementRoute, - readAllComputationIncomeStatementsRoute, - - ...$idComputationIncomeStatementRoutes, -] - +import { $idComputationIncomeStatementRoutes } from "../../../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/computationIncomeStatements/$idComputationIncomeStatement/$idComputationIncomeStatementRoutes.js" +import { createOneComputationIncomeStatementRoute } from "../../../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/computationIncomeStatements/createOneComputationIncomeStatement.js" +import { readAllComputationIncomeStatementsRoute } from "../../../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/computationIncomeStatements/readAllComputationIncomeStatements.js" + + +export const computationIncomeStatementsRoutes = [ + createOneComputationIncomeStatementRoute, + readAllComputationIncomeStatementsRoute, + + ...$idComputationIncomeStatementRoutes, +] + diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/computationIncomeStatements/createOneComputationIncomeStatement.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/computationIncomeStatements/createOneComputationIncomeStatement.ts index 4d3cc0b..3d4e7b1 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/computationIncomeStatements/createOneComputationIncomeStatement.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/computationIncomeStatements/createOneComputationIncomeStatement.ts @@ -1,10 +1,10 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { insertOne } from "#/utilities/sql/insertOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { createOneComputationIncomeStatementRouteDefinition } from "@arrhes/metadata/routes" -import { generateId } from "@arrhes/metadata/utilities" +import { authFactory } from "../../../../../../../../../../factories/authFactory.js" +import { response } from "../../../../../../../../../../utilities/response.js" +import { insertOne } from "../../../../../../../../../../utilities/sql/insertOne.js" +import { bodyValidator } from "../../../../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { createOneComputationIncomeStatementRouteDefinition } from "@arrhes/application-metadata/routes" +import { generateId } from "@arrhes/application-metadata/utilities" export const createOneComputationIncomeStatementRoute = authFactory.createApp() diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/computationIncomeStatements/readAllComputationIncomeStatements.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/computationIncomeStatements/readAllComputationIncomeStatements.ts index 7965ae2..177f4a0 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/computationIncomeStatements/readAllComputationIncomeStatements.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/computationIncomeStatements/readAllComputationIncomeStatements.ts @@ -1,9 +1,9 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { selectMany } from "#/utilities/sql/selectMany.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { readAllComputationIncomeStatementsRouteDefinition } from "@arrhes/metadata/routes" +import { authFactory } from "../../../../../../../../../../factories/authFactory.js" +import { response } from "../../../../../../../../../../utilities/response.js" +import { selectMany } from "../../../../../../../../../../utilities/sql/selectMany.js" +import { bodyValidator } from "../../../../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { readAllComputationIncomeStatementsRouteDefinition } from "@arrhes/application-metadata/routes" import { and, eq } from "drizzle-orm" diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/deleteOneComputation.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/deleteOneComputation.ts index c4d73ad..c496a51 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/deleteOneComputation.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/deleteOneComputation.ts @@ -1,9 +1,9 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { deleteOne } from "#/utilities/sql/deleteOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { deleteOneComputationRouteDefinition } from "@arrhes/metadata/routes" +import { authFactory } from "../../../../../../../../../factories/authFactory.js" +import { response } from "../../../../../../../../../utilities/response.js" +import { deleteOne } from "../../../../../../../../../utilities/sql/deleteOne.js" +import { bodyValidator } from "../../../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { deleteOneComputationRouteDefinition } from "@arrhes/application-metadata/routes" import { and, eq } from "drizzle-orm" diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/readOneComputation.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/readOneComputation.ts index e5ec483..f40b683 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/readOneComputation.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/readOneComputation.ts @@ -1,9 +1,9 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { selectOne } from "#/utilities/sql/selectOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { readOneComputationRouteDefinition } from "@arrhes/metadata/routes" +import { authFactory } from "../../../../../../../../../factories/authFactory.js" +import { response } from "../../../../../../../../../utilities/response.js" +import { selectOne } from "../../../../../../../../../utilities/sql/selectOne.js" +import { bodyValidator } from "../../../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { readOneComputationRouteDefinition } from "@arrhes/application-metadata/routes" import { and, eq } from "drizzle-orm" diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/updateOneComputation.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/updateOneComputation.ts index 551ae40..05196a1 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/updateOneComputation.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/updateOneComputation.ts @@ -1,9 +1,9 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { updateOne } from "#/utilities/sql/updateOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { updateOneComputationRouteDefinition } from "@arrhes/metadata/routes" +import { authFactory } from "../../../../../../../../../factories/authFactory.js" +import { response } from "../../../../../../../../../utilities/response.js" +import { updateOne } from "../../../../../../../../../utilities/sql/updateOne.js" +import { bodyValidator } from "../../../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { updateOneComputationRouteDefinition } from "@arrhes/application-metadata/routes" import { and, eq } from "drizzle-orm" diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/computationsRoutes.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/computationsRoutes.ts index 4edd213..55721f0 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/computationsRoutes.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/computationsRoutes.ts @@ -1,13 +1,13 @@ -import { $idComputationRoutes } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/$idComputationRoutes.js" -import { createOneComputationRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/createOneComputation.js" -import { generateComputationsRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/generateComputations.js" -import { readAllComputationsRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/readAllComputations.js" - - -export const computationsRoutes = [ - createOneComputationRoute, - readAllComputationsRoute, - generateComputationsRoute, - - ...$idComputationRoutes, -] +import { $idComputationRoutes } from "../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/$idComputation/$idComputationRoutes.js" +import { createOneComputationRoute } from "../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/createOneComputation.js" +import { generateComputationsRoute } from "../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/generateComputations.js" +import { readAllComputationsRoute } from "../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/readAllComputations.js" + + +export const computationsRoutes = [ + createOneComputationRoute, + readAllComputationsRoute, + generateComputationsRoute, + + ...$idComputationRoutes, +] diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/createOneComputation.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/createOneComputation.ts index adbaf32..29abf55 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/createOneComputation.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/createOneComputation.ts @@ -1,10 +1,10 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { insertOne } from "#/utilities/sql/insertOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { createOneComputationRouteDefinition } from "@arrhes/metadata/routes" -import { generateId } from "@arrhes/metadata/utilities" +import { authFactory } from "../../../../../../../../factories/authFactory.js" +import { response } from "../../../../../../../../utilities/response.js" +import { insertOne } from "../../../../../../../../utilities/sql/insertOne.js" +import { bodyValidator } from "../../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { createOneComputationRouteDefinition } from "@arrhes/application-metadata/routes" +import { generateId } from "@arrhes/application-metadata/utilities" export const createOneComputationRoute = authFactory.createApp() diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/generateComputations.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/generateComputations.ts index 74d4d97..a6a9cda 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/generateComputations.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/generateComputations.ts @@ -1,113 +1,113 @@ -import { authFactory } from "#/factories/authFactory.js" -import { Exception } from "#/utilities/exception.js" -import { response } from "#/utilities/response.js" -import { deleteMany } from "#/utilities/sql/deleteMany.js" -import { insertMany } from "#/utilities/sql/insertMany.js" -import { selectMany } from "#/utilities/sql/selectMany.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { defaultComputations } from "@arrhes/metadata/components" -import { models } from "@arrhes/metadata/models" -import { generateComputationsRouteDefinition } from "@arrhes/metadata/routes" -import { generateId } from "@arrhes/metadata/utilities" -import { and, eq } from "drizzle-orm" - - -export const generateComputationsRoute = authFactory.createApp() - .post( - generateComputationsRouteDefinition.path, - bodyValidator(generateComputationsRouteDefinition.schemas.body), - async (c) => { - const body = c.req.valid("json") - - const generatedComputations = await c.var.clients.sql.transaction(async (tx) => { - try { - const deletedComputations = await deleteMany({ - database: tx, - table: models.computation, - where: (table) => ( - and( - eq(table.idOrganization, body.idOrganization), - eq(table.idYear, body.idYear) - ) - ) - }) - } - catch (error: unknown) { - throw new Exception({ - internalMessage: "Failed to delete computations", - externalMessage: "Échec de la suppression des journaux", - }) - } - - const incomeStatements = await selectMany({ - database: tx, - table: models.incomeStatement, - where: (table) => ( - and( - eq(table.idOrganization, body.idOrganization), - eq(table.idYear, body.idYear) - ) - ) - }) - - const newComputationIncomeStatements: Array<(typeof models.computationIncomeStatement.$inferInsert)> = [] - let newComputations = defaultComputations.map((defaultComputation, defaultComputationIndex) => { - const newComputation = { - id: generateId(), - idOrganization: body.idOrganization, - idYear: body.idYear, - index: defaultComputationIndex, - number: defaultComputation.number.toString(), - label: defaultComputation.label, - createdAt: new Date().toISOString(), - lastUpdatedAt: null, - createdBy: null, - lastUpdatedBy: null, - } - - defaultComputation.incomeStatements.forEach((_incomeStatement, index) => { - const incomeStatement = incomeStatements.find((x) => x.number === _incomeStatement.number.toString()) - - if (incomeStatement === undefined) { - return - } - - newComputationIncomeStatements.push({ - id: generateId(), - idOrganization: body.idOrganization, - idYear: body.idYear, - idComputation: newComputation.id, - idIncomeStatement: incomeStatement.id, - index: index, - operation: _incomeStatement.operation, - createdAt: new Date().toISOString(), - }) - }) - - return newComputation - }) - - const generatedComputations = await insertMany({ - database: tx, - table: models.computation, - data: newComputations, - }) - - const generatedComputationIncomeStatements = await insertMany({ - database: tx, - table: models.computationIncomeStatement, - data: newComputationIncomeStatements, - }) - - return generatedComputations - }) - - - return response({ - context: c, - statusCode: 200, - schema: generateComputationsRouteDefinition.schemas.return, - data: generatedComputations, - }) - } +import { authFactory } from "../../../../../../../../factories/authFactory.js" +import { Exception } from "../../../../../../../../utilities/exception.js" +import { response } from "../../../../../../../../utilities/response.js" +import { deleteMany } from "../../../../../../../../utilities/sql/deleteMany.js" +import { insertMany } from "../../../../../../../../utilities/sql/insertMany.js" +import { selectMany } from "../../../../../../../../utilities/sql/selectMany.js" +import { bodyValidator } from "../../../../../../../../validators/bodyValidator.js" +import { defaultComputations } from "@arrhes/application-metadata/components" +import { models } from "@arrhes/application-metadata/models" +import { generateComputationsRouteDefinition } from "@arrhes/application-metadata/routes" +import { generateId } from "@arrhes/application-metadata/utilities" +import { and, eq } from "drizzle-orm" + + +export const generateComputationsRoute = authFactory.createApp() + .post( + generateComputationsRouteDefinition.path, + bodyValidator(generateComputationsRouteDefinition.schemas.body), + async (c) => { + const body = c.req.valid("json") + + const generatedComputations = await c.var.clients.sql.transaction(async (tx) => { + try { + const deletedComputations = await deleteMany({ + database: tx, + table: models.computation, + where: (table) => ( + and( + eq(table.idOrganization, body.idOrganization), + eq(table.idYear, body.idYear) + ) + ) + }) + } + catch (error: unknown) { + throw new Exception({ + internalMessage: "Failed to delete computations", + externalMessage: "Échec de la suppression des journaux", + }) + } + + const incomeStatements = await selectMany({ + database: tx, + table: models.incomeStatement, + where: (table) => ( + and( + eq(table.idOrganization, body.idOrganization), + eq(table.idYear, body.idYear) + ) + ) + }) + + const newComputationIncomeStatements: Array<(typeof models.computationIncomeStatement.$inferInsert)> = [] + let newComputations = defaultComputations.map((defaultComputation, defaultComputationIndex) => { + const newComputation = { + id: generateId(), + idOrganization: body.idOrganization, + idYear: body.idYear, + index: defaultComputationIndex, + number: defaultComputation.number.toString(), + label: defaultComputation.label, + createdAt: new Date().toISOString(), + lastUpdatedAt: null, + createdBy: null, + lastUpdatedBy: null, + } + + defaultComputation.incomeStatements.forEach((_incomeStatement, index) => { + const incomeStatement = incomeStatements.find((x) => x.number === _incomeStatement.number.toString()) + + if (incomeStatement === undefined) { + return + } + + newComputationIncomeStatements.push({ + id: generateId(), + idOrganization: body.idOrganization, + idYear: body.idYear, + idComputation: newComputation.id, + idIncomeStatement: incomeStatement.id, + index: index, + operation: _incomeStatement.operation, + createdAt: new Date().toISOString(), + }) + }) + + return newComputation + }) + + const generatedComputations = await insertMany({ + database: tx, + table: models.computation, + data: newComputations, + }) + + const generatedComputationIncomeStatements = await insertMany({ + database: tx, + table: models.computationIncomeStatement, + data: newComputationIncomeStatements, + }) + + return generatedComputations + }) + + + return response({ + context: c, + statusCode: 200, + schema: generateComputationsRouteDefinition.schemas.return, + data: generatedComputations, + }) + } ) \ No newline at end of file diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/readAllComputations.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/readAllComputations.ts index 9b19de5..a06591b 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/readAllComputations.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/readAllComputations.ts @@ -1,9 +1,9 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { selectMany } from "#/utilities/sql/selectMany.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { readAllComputationsRouteDefinition } from "@arrhes/metadata/routes" +import { authFactory } from "../../../../../../../../factories/authFactory.js" +import { response } from "../../../../../../../../utilities/response.js" +import { selectMany } from "../../../../../../../../utilities/sql/selectMany.js" +import { bodyValidator } from "../../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { readAllComputationsRouteDefinition } from "@arrhes/application-metadata/routes" import { and, eq } from "drizzle-orm" diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/general/closeYear.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/general/closeYear.ts index e92c653..9db24d7 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/general/closeYear.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/general/closeYear.ts @@ -1,9 +1,9 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { updateOne } from "#/utilities/sql/updateOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { closeYearRouteDefinition } from "@arrhes/metadata/routes" +import { authFactory } from "../../../../../../../../factories/authFactory.js" +import { response } from "../../../../../../../../utilities/response.js" +import { updateOne } from "../../../../../../../../utilities/sql/updateOne.js" +import { bodyValidator } from "../../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { closeYearRouteDefinition } from "@arrhes/application-metadata/routes" import { and, eq, not } from "drizzle-orm" diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/general/deleteOneYear.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/general/deleteOneYear.ts index 0112c0d..aebfd96 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/general/deleteOneYear.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/general/deleteOneYear.ts @@ -1,9 +1,9 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { deleteOne } from "#/utilities/sql/deleteOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { deleteOneYearRouteDefinition } from "@arrhes/metadata/routes" +import { authFactory } from "../../../../../../../../factories/authFactory.js" +import { response } from "../../../../../../../../utilities/response.js" +import { deleteOne } from "../../../../../../../../utilities/sql/deleteOne.js" +import { bodyValidator } from "../../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { deleteOneYearRouteDefinition } from "@arrhes/application-metadata/routes" import { and, eq } from "drizzle-orm" diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/general/generalRoutes.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/general/generalRoutes.ts index 85788c0..355a8d8 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/general/generalRoutes.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/general/generalRoutes.ts @@ -1,9 +1,9 @@ -import { closeYearRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/general/closeYear.js" -import { deleteOneYearRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/general/deleteOneYear.js" -import { openYearRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/general/openYear.js" -import { settleBalanceSheetRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/general/settleBalanceSheet.js" -import { settleIncomeStatementRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/general/settleIncomeStatement.js" -import { updateOneYearRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/general/updateOneYear.js" +import { closeYearRoute } from "../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/general/closeYear.js" +import { deleteOneYearRoute } from "../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/general/deleteOneYear.js" +import { openYearRoute } from "../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/general/openYear.js" +import { settleBalanceSheetRoute } from "../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/general/settleBalanceSheet.js" +import { settleIncomeStatementRoute } from "../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/general/settleIncomeStatement.js" +import { updateOneYearRoute } from "../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/general/updateOneYear.js" export const generalRoutes = [ diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/general/openYear.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/general/openYear.ts index 5a0e850..bf3296a 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/general/openYear.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/general/openYear.ts @@ -1,7 +1,7 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { openYearRouteDefinition } from "@arrhes/metadata/routes" +import { authFactory } from "../../../../../../../../factories/authFactory.js" +import { response } from "../../../../../../../../utilities/response.js" +import { bodyValidator } from "../../../../../../../../validators/bodyValidator.js" +import { openYearRouteDefinition } from "@arrhes/application-metadata/routes" export const openYearRoute = authFactory.createApp() diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/general/settleBalanceSheet.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/general/settleBalanceSheet.ts index d13b2ea..35f3738 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/general/settleBalanceSheet.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/general/settleBalanceSheet.ts @@ -1,7 +1,7 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { settleBalanceSheetRouteDefinition } from "@arrhes/metadata/routes" +import { authFactory } from "../../../../../../../../factories/authFactory.js" +import { response } from "../../../../../../../../utilities/response.js" +import { bodyValidator } from "../../../../../../../../validators/bodyValidator.js" +import { settleBalanceSheetRouteDefinition } from "@arrhes/application-metadata/routes" export const settleBalanceSheetRoute = authFactory.createApp() diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/general/settleIncomeStatement.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/general/settleIncomeStatement.ts index a8c79e6..67c0f08 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/general/settleIncomeStatement.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/general/settleIncomeStatement.ts @@ -1,7 +1,7 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { settleIncomeStatementRouteDefinition } from "@arrhes/metadata/routes" +import { authFactory } from "../../../../../../../../factories/authFactory.js" +import { response } from "../../../../../../../../utilities/response.js" +import { bodyValidator } from "../../../../../../../../validators/bodyValidator.js" +import { settleIncomeStatementRouteDefinition } from "@arrhes/application-metadata/routes" export const settleIncomeStatementRoute = authFactory.createApp() diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/general/updateOneYear.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/general/updateOneYear.ts index 0e4f3e2..dfd3e29 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/general/updateOneYear.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/general/updateOneYear.ts @@ -1,9 +1,9 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { updateOne } from "#/utilities/sql/updateOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { updateOneYearRouteDefinition } from "@arrhes/metadata/routes" +import { authFactory } from "../../../../../../../../factories/authFactory.js" +import { response } from "../../../../../../../../utilities/response.js" +import { updateOne } from "../../../../../../../../utilities/sql/updateOne.js" +import { bodyValidator } from "../../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { updateOneYearRouteDefinition } from "@arrhes/application-metadata/routes" import { and, eq } from "drizzle-orm" diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/incomeStatements/$idIncomeStatement/$idIncomeStatementRoutes.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/incomeStatements/$idIncomeStatement/$idIncomeStatementRoutes.ts index 0ca0924..2f05849 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/incomeStatements/$idIncomeStatement/$idIncomeStatementRoutes.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/incomeStatements/$idIncomeStatement/$idIncomeStatementRoutes.ts @@ -1,6 +1,6 @@ -import { deleteOneIncomeStatementRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/incomeStatements/$idIncomeStatement/deleteOneIncomeStatement.js"; -import { readOneIncomeStatementRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/incomeStatements/$idIncomeStatement/readOneIncomeStatement.js"; -import { updateOneIncomeStatementRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/incomeStatements/$idIncomeStatement/updateOneIncomeStatement.js"; +import { deleteOneIncomeStatementRoute } from "../../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/incomeStatements/$idIncomeStatement/deleteOneIncomeStatement.js"; +import { readOneIncomeStatementRoute } from "../../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/incomeStatements/$idIncomeStatement/readOneIncomeStatement.js"; +import { updateOneIncomeStatementRoute } from "../../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/incomeStatements/$idIncomeStatement/updateOneIncomeStatement.js"; export const $idIncomeStatementRoutes = [ diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/incomeStatements/$idIncomeStatement/deleteOneIncomeStatement.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/incomeStatements/$idIncomeStatement/deleteOneIncomeStatement.ts index 544e70f..c5051f6 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/incomeStatements/$idIncomeStatement/deleteOneIncomeStatement.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/incomeStatements/$idIncomeStatement/deleteOneIncomeStatement.ts @@ -1,9 +1,9 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { deleteOne } from "#/utilities/sql/deleteOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { deleteOneIncomeStatementRouteDefinition } from "@arrhes/metadata/routes" +import { authFactory } from "../../../../../../../../../factories/authFactory.js" +import { response } from "../../../../../../../../../utilities/response.js" +import { deleteOne } from "../../../../../../../../../utilities/sql/deleteOne.js" +import { bodyValidator } from "../../../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { deleteOneIncomeStatementRouteDefinition } from "@arrhes/application-metadata/routes" import { and, eq } from "drizzle-orm" diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/incomeStatements/$idIncomeStatement/readOneIncomeStatement.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/incomeStatements/$idIncomeStatement/readOneIncomeStatement.ts index b73a2fb..276f180 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/incomeStatements/$idIncomeStatement/readOneIncomeStatement.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/incomeStatements/$idIncomeStatement/readOneIncomeStatement.ts @@ -1,9 +1,9 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { selectOne } from "#/utilities/sql/selectOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { readOneIncomeStatementRouteDefinition } from "@arrhes/metadata/routes" +import { authFactory } from "../../../../../../../../../factories/authFactory.js" +import { response } from "../../../../../../../../../utilities/response.js" +import { selectOne } from "../../../../../../../../../utilities/sql/selectOne.js" +import { bodyValidator } from "../../../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { readOneIncomeStatementRouteDefinition } from "@arrhes/application-metadata/routes" import { and, eq } from "drizzle-orm" diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/incomeStatements/$idIncomeStatement/updateOneIncomeStatement.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/incomeStatements/$idIncomeStatement/updateOneIncomeStatement.ts index c201a34..6aedc2b 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/incomeStatements/$idIncomeStatement/updateOneIncomeStatement.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/incomeStatements/$idIncomeStatement/updateOneIncomeStatement.ts @@ -1,9 +1,9 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { updateOne } from "#/utilities/sql/updateOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { updateOneIncomeStatementRouteDefinition } from "@arrhes/metadata/routes" +import { authFactory } from "../../../../../../../../../factories/authFactory.js" +import { response } from "../../../../../../../../../utilities/response.js" +import { updateOne } from "../../../../../../../../../utilities/sql/updateOne.js" +import { bodyValidator } from "../../../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { updateOneIncomeStatementRouteDefinition } from "@arrhes/application-metadata/routes" import { and, eq } from "drizzle-orm" diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/incomeStatements/connectAccountsToIncomeStatements.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/incomeStatements/connectAccountsToIncomeStatements.ts index 8fc9e92..4bb7cfc 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/incomeStatements/connectAccountsToIncomeStatements.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/incomeStatements/connectAccountsToIncomeStatements.ts @@ -1,104 +1,104 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { selectMany } from "#/utilities/sql/selectMany.js" -import { selectOne } from "#/utilities/sql/selectOne.js" -import { updateOne } from "#/utilities/sql/updateOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { defaultAssociationIncomeStatements, defaultCompanyIncomeStatements } from "@arrhes/metadata/components" -import { models } from "@arrhes/metadata/models" -import { connectAccountsToIncomeStatementsRouteDefinition } from "@arrhes/metadata/routes" -import { and, eq } from "drizzle-orm" - - -export const connectAccountsToIncomeStatementsRoute = authFactory.createApp() - .post( - connectAccountsToIncomeStatementsRouteDefinition.path, - bodyValidator(connectAccountsToIncomeStatementsRouteDefinition.schemas.body), - async (c) => { - const body = c.req.valid("json") - - const readAllAccounts = await selectMany({ - database: c.var.clients.sql, - table: models.account, - where: (table) => ( - and( - eq(table.idOrganization, body.idOrganization), - eq(table.idYear, body.idYear), - ) - ) - }) - - const readAllIncomeStatements = await selectMany({ - database: c.var.clients.sql, - table: models.incomeStatement, - where: (table) => ( - and( - eq(table.idOrganization, body.idOrganization), - eq(table.idYear, body.idYear), - ) - ) - }) - - - const organization = await selectOne({ - database: c.var.clients.sql, - table: models.organization, - where: (table) => ( - eq(table.id, body.idOrganization) - ) - }) - const defaultIncomeStatements = ( - (organization.scope === "association") - ? defaultAssociationIncomeStatements - : defaultCompanyIncomeStatements - ) - - const connectAccountsToIncomeStatements = await c.var.clients.sql.transaction(async (tx) => { - for (const defaultIncomeStatement of defaultIncomeStatements) { - for (const defaultAccount of defaultIncomeStatement.accounts) { - - const foundAccount = readAllAccounts.find((account) => { - return account.number === defaultAccount.toString() - }) - - if (foundAccount === undefined) { - console.log("foundAccount is undefined", defaultIncomeStatement.number, defaultAccount) - continue - } - - const incomeStatement = readAllIncomeStatements.find((incomeStatement) => incomeStatement.number === defaultIncomeStatement.number.toString()) - if (incomeStatement === undefined) { - console.log("incomeStatement is undefined", defaultIncomeStatement.number) - continue - } - - const updateOneAccount = await updateOne({ - database: tx, - table: models.account, - data: { - idIncomeStatement: incomeStatement.id, - lastUpdatedAt: new Date().toISOString(), - lastUpdatedBy: c.var.user.id, - }, - where: (table) => ( - and( - eq(table.idOrganization, body.idOrganization), - eq(table.idYear, body.idYear), - eq(table.id, foundAccount.id), - ) - ) - }) - - } - } - }) - - - return response({ - context: c, - statusCode: 200, - schema: connectAccountsToIncomeStatementsRouteDefinition.schemas.return, - data: {}, - }) - } +import { authFactory } from "../../../../../../../../factories/authFactory.js" +import { response } from "../../../../../../../../utilities/response.js" +import { selectMany } from "../../../../../../../../utilities/sql/selectMany.js" +import { selectOne } from "../../../../../../../../utilities/sql/selectOne.js" +import { updateOne } from "../../../../../../../../utilities/sql/updateOne.js" +import { bodyValidator } from "../../../../../../../../validators/bodyValidator.js" +import { defaultAssociationIncomeStatements, defaultCompanyIncomeStatements } from "@arrhes/application-metadata/components" +import { models } from "@arrhes/application-metadata/models" +import { connectAccountsToIncomeStatementsRouteDefinition } from "@arrhes/application-metadata/routes" +import { and, eq } from "drizzle-orm" + + +export const connectAccountsToIncomeStatementsRoute = authFactory.createApp() + .post( + connectAccountsToIncomeStatementsRouteDefinition.path, + bodyValidator(connectAccountsToIncomeStatementsRouteDefinition.schemas.body), + async (c) => { + const body = c.req.valid("json") + + const readAllAccounts = await selectMany({ + database: c.var.clients.sql, + table: models.account, + where: (table) => ( + and( + eq(table.idOrganization, body.idOrganization), + eq(table.idYear, body.idYear), + ) + ) + }) + + const readAllIncomeStatements = await selectMany({ + database: c.var.clients.sql, + table: models.incomeStatement, + where: (table) => ( + and( + eq(table.idOrganization, body.idOrganization), + eq(table.idYear, body.idYear), + ) + ) + }) + + + const organization = await selectOne({ + database: c.var.clients.sql, + table: models.organization, + where: (table) => ( + eq(table.id, body.idOrganization) + ) + }) + const defaultIncomeStatements = ( + (organization.scope === "association") + ? defaultAssociationIncomeStatements + : defaultCompanyIncomeStatements + ) + + const connectAccountsToIncomeStatements = await c.var.clients.sql.transaction(async (tx) => { + for (const defaultIncomeStatement of defaultIncomeStatements) { + for (const defaultAccount of defaultIncomeStatement.accounts) { + + const foundAccount = readAllAccounts.find((account) => { + return account.number === defaultAccount.toString() + }) + + if (foundAccount === undefined) { + console.log("foundAccount is undefined", defaultIncomeStatement.number, defaultAccount) + continue + } + + const incomeStatement = readAllIncomeStatements.find((incomeStatement) => incomeStatement.number === defaultIncomeStatement.number.toString()) + if (incomeStatement === undefined) { + console.log("incomeStatement is undefined", defaultIncomeStatement.number) + continue + } + + const updateOneAccount = await updateOne({ + database: tx, + table: models.account, + data: { + idIncomeStatement: incomeStatement.id, + lastUpdatedAt: new Date().toISOString(), + lastUpdatedBy: c.var.user.id, + }, + where: (table) => ( + and( + eq(table.idOrganization, body.idOrganization), + eq(table.idYear, body.idYear), + eq(table.id, foundAccount.id), + ) + ) + }) + + } + } + }) + + + return response({ + context: c, + statusCode: 200, + schema: connectAccountsToIncomeStatementsRouteDefinition.schemas.return, + data: {}, + }) + } ) \ No newline at end of file diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/incomeStatements/createOneIncomeStatement.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/incomeStatements/createOneIncomeStatement.ts index 21184e5..0f2b4eb 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/incomeStatements/createOneIncomeStatement.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/incomeStatements/createOneIncomeStatement.ts @@ -1,10 +1,10 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { insertOne } from "#/utilities/sql/insertOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { createOneIncomeStatementRouteDefinition } from "@arrhes/metadata/routes" -import { generateId } from "@arrhes/metadata/utilities" +import { authFactory } from "../../../../../../../../factories/authFactory.js" +import { response } from "../../../../../../../../utilities/response.js" +import { insertOne } from "../../../../../../../../utilities/sql/insertOne.js" +import { bodyValidator } from "../../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { createOneIncomeStatementRouteDefinition } from "@arrhes/application-metadata/routes" +import { generateId } from "@arrhes/application-metadata/utilities" export const createOneIncomeStatementRoute = authFactory.createApp() diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/incomeStatements/generateIncomeStatements.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/incomeStatements/generateIncomeStatements.ts index 5ed792a..c3b7e24 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/incomeStatements/generateIncomeStatements.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/incomeStatements/generateIncomeStatements.ts @@ -1,100 +1,100 @@ -import { authFactory } from "#/factories/authFactory.js" -import { Exception } from "#/utilities/exception.js" -import { response } from "#/utilities/response.js" -import { deleteMany } from "#/utilities/sql/deleteMany.js" -import { insertMany } from "#/utilities/sql/insertMany.js" -import { selectOne } from "#/utilities/sql/selectOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { defaultAssociationIncomeStatements, defaultCompanyIncomeStatements } from "@arrhes/metadata/components" -import { models } from "@arrhes/metadata/models" -import { generateIncomeStatementsRouteDefinition } from "@arrhes/metadata/routes" -import { returnedSchemas } from "@arrhes/metadata/schemas" -import { generateId } from "@arrhes/metadata/utilities" -import { and, eq } from "drizzle-orm" -import * as v from "valibot" - - -export const generateIncomeStatementsRoute = authFactory.createApp() - .post( - generateIncomeStatementsRouteDefinition.path, - bodyValidator(generateIncomeStatementsRouteDefinition.schemas.body), - async (c) => { - const body = c.req.valid("json") - - const generatedIncomeStatements = await c.var.clients.sql.transaction(async (tx) => { - try { - const deletedIncomeStatements = await deleteMany({ - database: tx, - table: models.incomeStatement, - where: (table) => ( - and( - eq(table.idOrganization, body.idOrganization), - eq(table.idYear, body.idYear) - ) - ) - }) - } - catch (error: unknown) { - throw new Exception({ - internalMessage: "Failed to delete incomeStatements", - externalMessage: "Échec de la suppression des lignes de compte de résultat", - }) - } - - const organization = await selectOne({ - database: tx, - table: models.organization, - where: (table) => ( - eq(table.id, body.idOrganization) - ) - }) - const defaultIncomeStatements = ( - (organization.scope === "association") - ? defaultAssociationIncomeStatements - : defaultCompanyIncomeStatements - ) - - - const newIncomeStatements: Array> = [] - - defaultIncomeStatements - .forEach((defaultIncomeStatement) => { - const incomeStatementParent = newIncomeStatements.find((newIncomeStatement) => { - return newIncomeStatement.number === defaultIncomeStatement.numberParent?.toString() - }) - newIncomeStatements.push({ - id: generateId(), - idOrganization: body.idOrganization, - idYear: body.idYear, - idIncomeStatementParent: incomeStatementParent?.id ?? null, - number: defaultIncomeStatement.number.toString(), - isDefault: true, - isComputed: (incomeStatementParent === undefined) - ? true - : false, - label: defaultIncomeStatement.label, - createdAt: new Date().toISOString(), - lastUpdatedAt: null, - createdBy: null, - lastUpdatedBy: null, - }) - }) - - const generatedIncomeStatements = await insertMany({ - database: tx, - table: models.incomeStatement, - data: newIncomeStatements, - }) - - return generatedIncomeStatements - }) - - - return response({ - context: c, - statusCode: 200, - schema: generateIncomeStatementsRouteDefinition.schemas.return, - data: generatedIncomeStatements, - }) - } +import { authFactory } from "../../../../../../../../factories/authFactory.js" +import { Exception } from "../../../../../../../../utilities/exception.js" +import { response } from "../../../../../../../../utilities/response.js" +import { deleteMany } from "../../../../../../../../utilities/sql/deleteMany.js" +import { insertMany } from "../../../../../../../../utilities/sql/insertMany.js" +import { selectOne } from "../../../../../../../../utilities/sql/selectOne.js" +import { bodyValidator } from "../../../../../../../../validators/bodyValidator.js" +import { defaultAssociationIncomeStatements, defaultCompanyIncomeStatements } from "@arrhes/application-metadata/components" +import { models } from "@arrhes/application-metadata/models" +import { generateIncomeStatementsRouteDefinition } from "@arrhes/application-metadata/routes" +import { returnedSchemas } from "@arrhes/application-metadata/schemas" +import { generateId } from "@arrhes/application-metadata/utilities" +import { and, eq } from "drizzle-orm" +import * as v from "valibot" + + +export const generateIncomeStatementsRoute = authFactory.createApp() + .post( + generateIncomeStatementsRouteDefinition.path, + bodyValidator(generateIncomeStatementsRouteDefinition.schemas.body), + async (c) => { + const body = c.req.valid("json") + + const generatedIncomeStatements = await c.var.clients.sql.transaction(async (tx) => { + try { + const deletedIncomeStatements = await deleteMany({ + database: tx, + table: models.incomeStatement, + where: (table) => ( + and( + eq(table.idOrganization, body.idOrganization), + eq(table.idYear, body.idYear) + ) + ) + }) + } + catch (error: unknown) { + throw new Exception({ + internalMessage: "Failed to delete incomeStatements", + externalMessage: "Échec de la suppression des lignes de compte de résultat", + }) + } + + const organization = await selectOne({ + database: tx, + table: models.organization, + where: (table) => ( + eq(table.id, body.idOrganization) + ) + }) + const defaultIncomeStatements = ( + (organization.scope === "association") + ? defaultAssociationIncomeStatements + : defaultCompanyIncomeStatements + ) + + + const newIncomeStatements: Array> = [] + + defaultIncomeStatements + .forEach((defaultIncomeStatement) => { + const incomeStatementParent = newIncomeStatements.find((newIncomeStatement) => { + return newIncomeStatement.number === defaultIncomeStatement.numberParent?.toString() + }) + newIncomeStatements.push({ + id: generateId(), + idOrganization: body.idOrganization, + idYear: body.idYear, + idIncomeStatementParent: incomeStatementParent?.id ?? null, + number: defaultIncomeStatement.number.toString(), + isDefault: true, + isComputed: (incomeStatementParent === undefined) + ? true + : false, + label: defaultIncomeStatement.label, + createdAt: new Date().toISOString(), + lastUpdatedAt: null, + createdBy: null, + lastUpdatedBy: null, + }) + }) + + const generatedIncomeStatements = await insertMany({ + database: tx, + table: models.incomeStatement, + data: newIncomeStatements, + }) + + return generatedIncomeStatements + }) + + + return response({ + context: c, + statusCode: 200, + schema: generateIncomeStatementsRouteDefinition.schemas.return, + data: generatedIncomeStatements, + }) + } ) \ No newline at end of file diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/incomeStatements/incomeStatementsRoutes.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/incomeStatements/incomeStatementsRoutes.ts index 89d0a18..6379065 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/incomeStatements/incomeStatementsRoutes.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/incomeStatements/incomeStatementsRoutes.ts @@ -1,8 +1,8 @@ -import { $idIncomeStatementRoutes } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/incomeStatements/$idIncomeStatement/$idIncomeStatementRoutes.js" -import { connectAccountsToIncomeStatementsRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/incomeStatements/connectAccountsToIncomeStatements.js" -import { createOneIncomeStatementRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/incomeStatements/createOneIncomeStatement.js" -import { generateIncomeStatementsRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/incomeStatements/generateIncomeStatements.js" -import { readAllIncomeStatementsRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/incomeStatements/readAllIncomeStatements.js" +import { $idIncomeStatementRoutes } from "../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/incomeStatements/$idIncomeStatement/$idIncomeStatementRoutes.js" +import { connectAccountsToIncomeStatementsRoute } from "../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/incomeStatements/connectAccountsToIncomeStatements.js" +import { createOneIncomeStatementRoute } from "../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/incomeStatements/createOneIncomeStatement.js" +import { generateIncomeStatementsRoute } from "../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/incomeStatements/generateIncomeStatements.js" +import { readAllIncomeStatementsRoute } from "../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/incomeStatements/readAllIncomeStatements.js" export const incomeStatementsRoutes = [ diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/incomeStatements/readAllIncomeStatements.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/incomeStatements/readAllIncomeStatements.ts index 84ae51c..8dc1c43 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/incomeStatements/readAllIncomeStatements.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/incomeStatements/readAllIncomeStatements.ts @@ -1,9 +1,9 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { selectMany } from "#/utilities/sql/selectMany.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { readAllIncomeStatementsRouteDefinition } from "@arrhes/metadata/routes" +import { authFactory } from "../../../../../../../../factories/authFactory.js" +import { response } from "../../../../../../../../utilities/response.js" +import { selectMany } from "../../../../../../../../utilities/sql/selectMany.js" +import { bodyValidator } from "../../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { readAllIncomeStatementsRouteDefinition } from "@arrhes/application-metadata/routes" import { and, eq } from "drizzle-orm" diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/journals/$idJournal/$idJournalRoute.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/journals/$idJournal/$idJournalRoute.ts index 2707641..40adacd 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/journals/$idJournal/$idJournalRoute.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/journals/$idJournal/$idJournalRoute.ts @@ -1,6 +1,6 @@ -import { deleteOneJournalRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/journals/$idJournal/deleteOneJournal.js" -import { readOneJournalRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/journals/$idJournal/readOneJournal.js" -import { updateOneJournalRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/journals/$idJournal/updateOneJournal.js" +import { deleteOneJournalRoute } from "../../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/journals/$idJournal/deleteOneJournal.js" +import { readOneJournalRoute } from "../../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/journals/$idJournal/readOneJournal.js" +import { updateOneJournalRoute } from "../../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/journals/$idJournal/updateOneJournal.js" export const $idJournalRoutes = [ diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/journals/$idJournal/deleteOneJournal.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/journals/$idJournal/deleteOneJournal.ts index 639986b..898343e 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/journals/$idJournal/deleteOneJournal.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/journals/$idJournal/deleteOneJournal.ts @@ -1,9 +1,9 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { deleteOne } from "#/utilities/sql/deleteOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { deleteOneJournalRouteDefinition } from "@arrhes/metadata/routes" +import { authFactory } from "../../../../../../../../../factories/authFactory.js" +import { response } from "../../../../../../../../../utilities/response.js" +import { deleteOne } from "../../../../../../../../../utilities/sql/deleteOne.js" +import { bodyValidator } from "../../../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { deleteOneJournalRouteDefinition } from "@arrhes/application-metadata/routes" import { and, eq } from "drizzle-orm" diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/journals/$idJournal/readOneJournal.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/journals/$idJournal/readOneJournal.ts index 1e6fe16..a535006 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/journals/$idJournal/readOneJournal.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/journals/$idJournal/readOneJournal.ts @@ -1,9 +1,9 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { selectOne } from "#/utilities/sql/selectOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { readOneJournalRouteDefinition } from "@arrhes/metadata/routes" +import { authFactory } from "../../../../../../../../../factories/authFactory.js" +import { response } from "../../../../../../../../../utilities/response.js" +import { selectOne } from "../../../../../../../../../utilities/sql/selectOne.js" +import { bodyValidator } from "../../../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { readOneJournalRouteDefinition } from "@arrhes/application-metadata/routes" import { and, eq } from "drizzle-orm" diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/journals/$idJournal/updateOneJournal.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/journals/$idJournal/updateOneJournal.ts index 6d9fd40..d05fbd3 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/journals/$idJournal/updateOneJournal.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/journals/$idJournal/updateOneJournal.ts @@ -1,9 +1,9 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { updateOne } from "#/utilities/sql/updateOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { updateOneJournalRouteDefinition } from "@arrhes/metadata/routes" +import { authFactory } from "../../../../../../../../../factories/authFactory.js" +import { response } from "../../../../../../../../../utilities/response.js" +import { updateOne } from "../../../../../../../../../utilities/sql/updateOne.js" +import { bodyValidator } from "../../../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { updateOneJournalRouteDefinition } from "@arrhes/application-metadata/routes" import { and, eq } from "drizzle-orm" diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/journals/createOneJournal.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/journals/createOneJournal.ts index 460a750..2e07e1b 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/journals/createOneJournal.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/journals/createOneJournal.ts @@ -1,10 +1,10 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { insertOne } from "#/utilities/sql/insertOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { createOneJournalRouteDefinition } from "@arrhes/metadata/routes" -import { generateId } from "@arrhes/metadata/utilities" +import { authFactory } from "../../../../../../../../factories/authFactory.js" +import { response } from "../../../../../../../../utilities/response.js" +import { insertOne } from "../../../../../../../../utilities/sql/insertOne.js" +import { bodyValidator } from "../../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { createOneJournalRouteDefinition } from "@arrhes/application-metadata/routes" +import { generateId } from "@arrhes/application-metadata/utilities" export const createOneJournalRoute = authFactory.createApp() diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/journals/generateJournals.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/journals/generateJournals.ts index cb6c909..a17a0b1 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/journals/generateJournals.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/journals/generateJournals.ts @@ -1,71 +1,71 @@ -import { authFactory } from "#/factories/authFactory.js" -import { Exception } from "#/utilities/exception.js" -import { response } from "#/utilities/response.js" -import { deleteMany } from "#/utilities/sql/deleteMany.js" -import { insertMany } from "#/utilities/sql/insertMany.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { defaultJournals } from "@arrhes/metadata/components" -import { models } from "@arrhes/metadata/models" -import { generateJournalsRouteDefinition } from "@arrhes/metadata/routes" -import { generateId } from "@arrhes/metadata/utilities" -import { and, eq } from "drizzle-orm" - - -export const generateJournalsRoute = authFactory.createApp() - .post( - generateJournalsRouteDefinition.path, - bodyValidator(generateJournalsRouteDefinition.schemas.body), - async (c) => { - const body = c.req.valid("json") - - const generatedJournals = await c.var.clients.sql.transaction(async (tx) => { - try { - const deletedJournals = await deleteMany({ - database: tx, - table: models.journal, - where: (table) => ( - and( - eq(table.idOrganization, body.idOrganization), - eq(table.idYear, body.idYear) - ) - ) - }) - } - catch (error: unknown) { - throw new Exception({ - internalMessage: "Failed to delete journals", - externalMessage: "Échec de la suppression des journaux", - }) - } - - let newJournals = defaultJournals.map((defaultJournal) => { - return ({ - id: generateId(), - idOrganization: body.idOrganization, - idYear: body.idYear, - code: defaultJournal.code, - label: defaultJournal.label, - createdAt: new Date().toISOString(), - lastUpdatedAt: null, - createdBy: null, - lastUpdatedBy: null, - }) - }) - - const generatedJournals = await insertMany({ - database: tx, - table: models.journal, - data: newJournals, - }) - - return generatedJournals - }) - - return response({ - context: c, - statusCode: 200, - schema: generateJournalsRouteDefinition.schemas.return, - data: generatedJournals, - }) - } +import { authFactory } from "../../../../../../../../factories/authFactory.js" +import { Exception } from "../../../../../../../../utilities/exception.js" +import { response } from "../../../../../../../../utilities/response.js" +import { deleteMany } from "../../../../../../../../utilities/sql/deleteMany.js" +import { insertMany } from "../../../../../../../../utilities/sql/insertMany.js" +import { bodyValidator } from "../../../../../../../../validators/bodyValidator.js" +import { defaultJournals } from "@arrhes/application-metadata/components" +import { models } from "@arrhes/application-metadata/models" +import { generateJournalsRouteDefinition } from "@arrhes/application-metadata/routes" +import { generateId } from "@arrhes/application-metadata/utilities" +import { and, eq } from "drizzle-orm" + + +export const generateJournalsRoute = authFactory.createApp() + .post( + generateJournalsRouteDefinition.path, + bodyValidator(generateJournalsRouteDefinition.schemas.body), + async (c) => { + const body = c.req.valid("json") + + const generatedJournals = await c.var.clients.sql.transaction(async (tx) => { + try { + const deletedJournals = await deleteMany({ + database: tx, + table: models.journal, + where: (table) => ( + and( + eq(table.idOrganization, body.idOrganization), + eq(table.idYear, body.idYear) + ) + ) + }) + } + catch (error: unknown) { + throw new Exception({ + internalMessage: "Failed to delete journals", + externalMessage: "Échec de la suppression des journaux", + }) + } + + let newJournals = defaultJournals.map((defaultJournal) => { + return ({ + id: generateId(), + idOrganization: body.idOrganization, + idYear: body.idYear, + code: defaultJournal.code, + label: defaultJournal.label, + createdAt: new Date().toISOString(), + lastUpdatedAt: null, + createdBy: null, + lastUpdatedBy: null, + }) + }) + + const generatedJournals = await insertMany({ + database: tx, + table: models.journal, + data: newJournals, + }) + + return generatedJournals + }) + + return response({ + context: c, + statusCode: 200, + schema: generateJournalsRouteDefinition.schemas.return, + data: generatedJournals, + }) + } ) \ No newline at end of file diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/journals/journalsRoutes.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/journals/journalsRoutes.ts index 3b93790..cb60737 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/journals/journalsRoutes.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/journals/journalsRoutes.ts @@ -1,7 +1,7 @@ -import { $idJournalRoutes } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/journals/$idJournal/$idJournalRoute.js" -import { createOneJournalRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/journals/createOneJournal.js" -import { generateJournalsRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/journals/generateJournals.js" -import { readAllJournalsRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/journals/readAllJournals.js" +import { $idJournalRoutes } from "../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/journals/$idJournal/$idJournalRoute.js" +import { createOneJournalRoute } from "../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/journals/createOneJournal.js" +import { generateJournalsRoute } from "../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/journals/generateJournals.js" +import { readAllJournalsRoute } from "../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/journals/readAllJournals.js" export const journalsRoutes = [ diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/journals/readAllJournals.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/journals/readAllJournals.ts index 7882562..55b07f5 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/journals/readAllJournals.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/journals/readAllJournals.ts @@ -1,9 +1,9 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { selectMany } from "#/utilities/sql/selectMany.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { readAllJournalsRouteDefinition } from "@arrhes/metadata/routes" +import { authFactory } from "../../../../../../../../factories/authFactory.js" +import { response } from "../../../../../../../../utilities/response.js" +import { selectMany } from "../../../../../../../../utilities/sql/selectMany.js" +import { bodyValidator } from "../../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { readAllJournalsRouteDefinition } from "@arrhes/application-metadata/routes" import { and, eq } from "drizzle-orm" diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/recordLabels/$idRecordLabel/$idRecordLabelRoutes.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/recordLabels/$idRecordLabel/$idRecordLabelRoutes.ts index 4170c3d..5699dc4 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/recordLabels/$idRecordLabel/$idRecordLabelRoutes.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/recordLabels/$idRecordLabel/$idRecordLabelRoutes.ts @@ -1,10 +1,10 @@ -import { deleteOneRecordLabelRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/recordLabels/$idRecordLabel/deleteOneRecordLabel.js" -import { readOneRecordLabelRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/recordLabels/$idRecordLabel/readOneRecordLabel.js" -import { updateOneRecordLabelRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/recordLabels/$idRecordLabel/updateOneRecordLabel.js" - - -export const $idRecordLabelRoutes = [ - deleteOneRecordLabelRoute, - readOneRecordLabelRoute, - updateOneRecordLabelRoute, +import { deleteOneRecordLabelRoute } from "../../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/recordLabels/$idRecordLabel/deleteOneRecordLabel.js" +import { readOneRecordLabelRoute } from "../../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/recordLabels/$idRecordLabel/readOneRecordLabel.js" +import { updateOneRecordLabelRoute } from "../../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/recordLabels/$idRecordLabel/updateOneRecordLabel.js" + + +export const $idRecordLabelRoutes = [ + deleteOneRecordLabelRoute, + readOneRecordLabelRoute, + updateOneRecordLabelRoute, ] \ No newline at end of file diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/recordLabels/$idRecordLabel/deleteOneRecordLabel.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/recordLabels/$idRecordLabel/deleteOneRecordLabel.ts index 690b9b3..1043008 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/recordLabels/$idRecordLabel/deleteOneRecordLabel.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/recordLabels/$idRecordLabel/deleteOneRecordLabel.ts @@ -1,36 +1,36 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { deleteOne } from "#/utilities/sql/deleteOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { deleteOneRecordLabelRouteDefinition } from "@arrhes/metadata/routes" -import { and, eq } from "drizzle-orm" - - -export const deleteOneRecordLabelRoute = authFactory.createApp() - .post( - deleteOneRecordLabelRouteDefinition.path, - bodyValidator(deleteOneRecordLabelRouteDefinition.schemas.body), - async (c) => { - const body = c.req.valid("json") - - const deleteOneRecordLabel = await deleteOne({ - database: c.var.clients.sql, - table: models.recordLabel, - where: (table) => ( - and( - eq(table.idOrganization, body.idOrganization), - eq(table.idYear, body.idYear), - eq(table.id, body.idRecordLabel), - ) - ) - }) - - return response({ - context: c, - statusCode: 200, - schema: deleteOneRecordLabelRouteDefinition.schemas.return, - data: deleteOneRecordLabel, - }) - } +import { authFactory } from "../../../../../../../../../factories/authFactory.js" +import { response } from "../../../../../../../../../utilities/response.js" +import { deleteOne } from "../../../../../../../../../utilities/sql/deleteOne.js" +import { bodyValidator } from "../../../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { deleteOneRecordLabelRouteDefinition } from "@arrhes/application-metadata/routes" +import { and, eq } from "drizzle-orm" + + +export const deleteOneRecordLabelRoute = authFactory.createApp() + .post( + deleteOneRecordLabelRouteDefinition.path, + bodyValidator(deleteOneRecordLabelRouteDefinition.schemas.body), + async (c) => { + const body = c.req.valid("json") + + const deleteOneRecordLabel = await deleteOne({ + database: c.var.clients.sql, + table: models.recordLabel, + where: (table) => ( + and( + eq(table.idOrganization, body.idOrganization), + eq(table.idYear, body.idYear), + eq(table.id, body.idRecordLabel), + ) + ) + }) + + return response({ + context: c, + statusCode: 200, + schema: deleteOneRecordLabelRouteDefinition.schemas.return, + data: deleteOneRecordLabel, + }) + } ) \ No newline at end of file diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/recordLabels/$idRecordLabel/readOneRecordLabel.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/recordLabels/$idRecordLabel/readOneRecordLabel.ts index 2a18d7f..1b76aaa 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/recordLabels/$idRecordLabel/readOneRecordLabel.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/recordLabels/$idRecordLabel/readOneRecordLabel.ts @@ -1,37 +1,37 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { selectOne } from "#/utilities/sql/selectOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { readOneRecordLabelRouteDefinition } from "@arrhes/metadata/routes" -import { and, eq } from "drizzle-orm" - - -export const readOneRecordLabelRoute = authFactory.createApp() - .post( - readOneRecordLabelRouteDefinition.path, - bodyValidator(readOneRecordLabelRouteDefinition.schemas.body), - async (c) => { - - const body = c.req.valid("json") - - const readOneRecordLabel = await selectOne({ - database: c.var.clients.sql, - table: models.recordLabel, - where: (table) => ( - and( - eq(table.idOrganization, body.idOrganization), - eq(table.idYear, body.idYear), - eq(table.id, body.idRecordLabel), - ) - ) - }) - - return response({ - context: c, - statusCode: 200, - schema: readOneRecordLabelRouteDefinition.schemas.return, - data: readOneRecordLabel, - }) - } +import { authFactory } from "../../../../../../../../../factories/authFactory.js" +import { response } from "../../../../../../../../../utilities/response.js" +import { selectOne } from "../../../../../../../../../utilities/sql/selectOne.js" +import { bodyValidator } from "../../../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { readOneRecordLabelRouteDefinition } from "@arrhes/application-metadata/routes" +import { and, eq } from "drizzle-orm" + + +export const readOneRecordLabelRoute = authFactory.createApp() + .post( + readOneRecordLabelRouteDefinition.path, + bodyValidator(readOneRecordLabelRouteDefinition.schemas.body), + async (c) => { + + const body = c.req.valid("json") + + const readOneRecordLabel = await selectOne({ + database: c.var.clients.sql, + table: models.recordLabel, + where: (table) => ( + and( + eq(table.idOrganization, body.idOrganization), + eq(table.idYear, body.idYear), + eq(table.id, body.idRecordLabel), + ) + ) + }) + + return response({ + context: c, + statusCode: 200, + schema: readOneRecordLabelRouteDefinition.schemas.return, + data: readOneRecordLabel, + }) + } ) \ No newline at end of file diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/recordLabels/$idRecordLabel/updateOneRecordLabel.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/recordLabels/$idRecordLabel/updateOneRecordLabel.ts index ffcc07d..76f6d3b 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/recordLabels/$idRecordLabel/updateOneRecordLabel.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/recordLabels/$idRecordLabel/updateOneRecordLabel.ts @@ -1,43 +1,43 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { updateOne } from "#/utilities/sql/updateOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { updateOneRecordLabelRouteDefinition } from "@arrhes/metadata/routes" -import { and, eq } from "drizzle-orm" - - -export const updateOneRecordLabelRoute = authFactory.createApp() - .post( - updateOneRecordLabelRouteDefinition.path, - bodyValidator(updateOneRecordLabelRouteDefinition.schemas.body), - async (c) => { - - const body = c.req.valid("json") - - const updateOneRecordLabel = await updateOne({ - database: c.var.clients.sql, - table: models.recordLabel, - data: { - label: body.label, - - lastUpdatedAt: new Date().toISOString(), - lastUpdatedBy: c.var.user.id, - }, - where: (table) => ( - and( - eq(table.idOrganization, body.idOrganization), - eq(table.idYear, body.idYear), - eq(table.id, body.idRecordLabel), - ) - ) - }) - - return response({ - context: c, - statusCode: 200, - schema: updateOneRecordLabelRouteDefinition.schemas.return, - data: updateOneRecordLabel, - }) - } +import { authFactory } from "../../../../../../../../../factories/authFactory.js" +import { response } from "../../../../../../../../../utilities/response.js" +import { updateOne } from "../../../../../../../../../utilities/sql/updateOne.js" +import { bodyValidator } from "../../../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { updateOneRecordLabelRouteDefinition } from "@arrhes/application-metadata/routes" +import { and, eq } from "drizzle-orm" + + +export const updateOneRecordLabelRoute = authFactory.createApp() + .post( + updateOneRecordLabelRouteDefinition.path, + bodyValidator(updateOneRecordLabelRouteDefinition.schemas.body), + async (c) => { + + const body = c.req.valid("json") + + const updateOneRecordLabel = await updateOne({ + database: c.var.clients.sql, + table: models.recordLabel, + data: { + label: body.label, + + lastUpdatedAt: new Date().toISOString(), + lastUpdatedBy: c.var.user.id, + }, + where: (table) => ( + and( + eq(table.idOrganization, body.idOrganization), + eq(table.idYear, body.idYear), + eq(table.id, body.idRecordLabel), + ) + ) + }) + + return response({ + context: c, + statusCode: 200, + schema: updateOneRecordLabelRouteDefinition.schemas.return, + data: updateOneRecordLabel, + }) + } ) \ No newline at end of file diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/recordLabels/createOneRecordLabel.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/recordLabels/createOneRecordLabel.ts index 9322043..e021292 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/recordLabels/createOneRecordLabel.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/recordLabels/createOneRecordLabel.ts @@ -1,41 +1,41 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { insertOne } from "#/utilities/sql/insertOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { createOneRecordLabelRouteDefinition } from "@arrhes/metadata/routes" -import { generateId } from "@arrhes/metadata/utilities" - - -export const createOneRecordLabelRoute = authFactory.createApp() - .post( - createOneRecordLabelRouteDefinition.path, - bodyValidator(createOneRecordLabelRouteDefinition.schemas.body), - async (c) => { - const body = c.req.valid("json") - - const createOneRecordLabel = await insertOne({ - database: c.var.clients.sql, - table: models.recordLabel, - data: { - id: generateId(), - idOrganization: body.idOrganization, - idYear: body.idYear, - - label: body.label, - - createdAt: new Date().toISOString(), - lastUpdatedAt: null, - createdBy: c.var.user.id, - lastUpdatedBy: null, - } - }) - - return response({ - context: c, - statusCode: 200, - schema: createOneRecordLabelRouteDefinition.schemas.return, - data: createOneRecordLabel, - }) - } +import { authFactory } from "../../../../../../../../factories/authFactory.js" +import { response } from "../../../../../../../../utilities/response.js" +import { insertOne } from "../../../../../../../../utilities/sql/insertOne.js" +import { bodyValidator } from "../../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { createOneRecordLabelRouteDefinition } from "@arrhes/application-metadata/routes" +import { generateId } from "@arrhes/application-metadata/utilities" + + +export const createOneRecordLabelRoute = authFactory.createApp() + .post( + createOneRecordLabelRouteDefinition.path, + bodyValidator(createOneRecordLabelRouteDefinition.schemas.body), + async (c) => { + const body = c.req.valid("json") + + const createOneRecordLabel = await insertOne({ + database: c.var.clients.sql, + table: models.recordLabel, + data: { + id: generateId(), + idOrganization: body.idOrganization, + idYear: body.idYear, + + label: body.label, + + createdAt: new Date().toISOString(), + lastUpdatedAt: null, + createdBy: c.var.user.id, + lastUpdatedBy: null, + } + }) + + return response({ + context: c, + statusCode: 200, + schema: createOneRecordLabelRouteDefinition.schemas.return, + data: createOneRecordLabel, + }) + } ) \ No newline at end of file diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/recordLabels/readAllRecordLabels.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/recordLabels/readAllRecordLabels.ts index b4f76fa..64aae90 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/recordLabels/readAllRecordLabels.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/recordLabels/readAllRecordLabels.ts @@ -1,35 +1,35 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { selectMany } from "#/utilities/sql/selectMany.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { readAllRecordLabelsRouteDefinition } from "@arrhes/metadata/routes" -import { and, eq } from "drizzle-orm" - - -export const readAllRecordLabelsRoute = authFactory.createApp() - .post( - readAllRecordLabelsRouteDefinition.path, - bodyValidator(readAllRecordLabelsRouteDefinition.schemas.body), - async (c) => { - const body = c.req.valid("json") - - const readAllRecordLabels = await selectMany({ - database: c.var.clients.sql, - table: models.recordLabel, - where: (table) => ( - and( - eq(table.idOrganization, body.idOrganization), - eq(table.idYear, body.idYear), - ) - ) - }) - - return response({ - context: c, - statusCode: 200, - schema: readAllRecordLabelsRouteDefinition.schemas.return, - data: readAllRecordLabels, - }) - } +import { authFactory } from "../../../../../../../../factories/authFactory.js" +import { response } from "../../../../../../../../utilities/response.js" +import { selectMany } from "../../../../../../../../utilities/sql/selectMany.js" +import { bodyValidator } from "../../../../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { readAllRecordLabelsRouteDefinition } from "@arrhes/application-metadata/routes" +import { and, eq } from "drizzle-orm" + + +export const readAllRecordLabelsRoute = authFactory.createApp() + .post( + readAllRecordLabelsRouteDefinition.path, + bodyValidator(readAllRecordLabelsRouteDefinition.schemas.body), + async (c) => { + const body = c.req.valid("json") + + const readAllRecordLabels = await selectMany({ + database: c.var.clients.sql, + table: models.recordLabel, + where: (table) => ( + and( + eq(table.idOrganization, body.idOrganization), + eq(table.idYear, body.idYear), + ) + ) + }) + + return response({ + context: c, + statusCode: 200, + schema: readAllRecordLabelsRouteDefinition.schemas.return, + data: readAllRecordLabels, + }) + } ) \ No newline at end of file diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/recordLabels/recordLabelsRoutes.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/recordLabels/recordLabelsRoutes.ts index 23c2390..c731d76 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/recordLabels/recordLabelsRoutes.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/recordLabels/recordLabelsRoutes.ts @@ -1,11 +1,11 @@ -import { $idRecordLabelRoutes } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/recordLabels/$idRecordLabel/$idRecordLabelRoutes.js" -import { createOneRecordLabelRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/recordLabels/createOneRecordLabel.js" -import { readAllRecordLabelsRoute } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/recordLabels/readAllRecordLabels.js" - - -export const recordLabelsRoutes = [ - createOneRecordLabelRoute, - readAllRecordLabelsRoute, - - ...$idRecordLabelRoutes, +import { $idRecordLabelRoutes } from "../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/recordLabels/$idRecordLabel/$idRecordLabelRoutes.js" +import { createOneRecordLabelRoute } from "../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/recordLabels/createOneRecordLabel.js" +import { readAllRecordLabelsRoute } from "../../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/recordLabels/readAllRecordLabels.js" + + +export const recordLabelsRoutes = [ + createOneRecordLabelRoute, + readAllRecordLabelsRoute, + + ...$idRecordLabelRoutes, ] \ No newline at end of file diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/yearSettingsRoute.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/yearSettingsRoute.ts index 0598f43..5a11f91 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/yearSettingsRoute.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/yearSettingsRoute.ts @@ -1,10 +1,10 @@ -import { accountsRoutes } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/accounts/accountsRoutes.js" -import { balanceSheetsRoutes } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/balanceSheets/balanceSheetsRoutes.js" -import { computationsRoutes } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/computationsRoutes.js" -import { generalRoutes } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/general/generalRoutes.js" -import { incomeStatementsRoutes } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/incomeStatements/incomeStatementsRoutes.js" -import { journalsRoutes } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/journals/journalsRoutes.js" -import { recordLabelsRoutes } from "#/routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/recordLabels/recordLabelsRoutes.js" +import { accountsRoutes } from "../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/accounts/accountsRoutes.js" +import { balanceSheetsRoutes } from "../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/balanceSheets/balanceSheetsRoutes.js" +import { computationsRoutes } from "../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/computations/computationsRoutes.js" +import { generalRoutes } from "../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/general/generalRoutes.js" +import { incomeStatementsRoutes } from "../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/incomeStatements/incomeStatementsRoutes.js" +import { journalsRoutes } from "../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/journals/journalsRoutes.js" +import { recordLabelsRoutes } from "../../../../../../../routes/auth/organizations/$idOrganization/years/$idYear/yearSettings/recordLabels/recordLabelsRoutes.js" export const yearSettingsRoute = [ diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/createOneYear.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/createOneYear.ts index a2673e3..bd02a41 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/createOneYear.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/createOneYear.ts @@ -1,10 +1,10 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { insertOne } from "#/utilities/sql/insertOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { createOneYearRouteDefinition } from "@arrhes/metadata/routes" -import { generateId } from "@arrhes/metadata/utilities" +import { authFactory } from "../../../../../factories/authFactory.js" +import { response } from "../../../../../utilities/response.js" +import { insertOne } from "../../../../../utilities/sql/insertOne.js" +import { bodyValidator } from "../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { createOneYearRouteDefinition } from "@arrhes/application-metadata/routes" +import { generateId } from "@arrhes/application-metadata/utilities" export const createOneYearRoute = authFactory.createApp() diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/readAllYears.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/readAllYears.ts index 1edd512..85026a3 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/readAllYears.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/readAllYears.ts @@ -1,9 +1,9 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { selectMany } from "#/utilities/sql/selectMany.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { readAllYearsRouteDefinition } from "@arrhes/metadata/routes" +import { authFactory } from "../../../../../factories/authFactory.js" +import { response } from "../../../../../utilities/response.js" +import { selectMany } from "../../../../../utilities/sql/selectMany.js" +import { bodyValidator } from "../../../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { readAllYearsRouteDefinition } from "@arrhes/application-metadata/routes" import { and, eq } from "drizzle-orm" diff --git a/packages/api/src/routes/auth/organizations/$idOrganization/years/yearsRoutes.ts b/packages/api/src/routes/auth/organizations/$idOrganization/years/yearsRoutes.ts index 6617e46..a6cd038 100644 --- a/packages/api/src/routes/auth/organizations/$idOrganization/years/yearsRoutes.ts +++ b/packages/api/src/routes/auth/organizations/$idOrganization/years/yearsRoutes.ts @@ -1,11 +1,11 @@ -import { $idYearRoutes } from "#/routes/auth/organizations/$idOrganization/years/$idYear/$idYearRoutes.js" -import { createOneYearRoute } from "#/routes/auth/organizations/$idOrganization/years/createOneYear.js" -import { readAllYearsRoute } from "#/routes/auth/organizations/$idOrganization/years/readAllYears.js" - - -export const yearsRoutes = [ - createOneYearRoute, - readAllYearsRoute, - - ...$idYearRoutes, +import { $idYearRoutes } from "../../../../../routes/auth/organizations/$idOrganization/years/$idYear/$idYearRoutes.js" +import { createOneYearRoute } from "../../../../../routes/auth/organizations/$idOrganization/years/createOneYear.js" +import { readAllYearsRoute } from "../../../../../routes/auth/organizations/$idOrganization/years/readAllYears.js" + + +export const yearsRoutes = [ + createOneYearRoute, + readAllYearsRoute, + + ...$idYearRoutes, ] \ No newline at end of file diff --git a/packages/api/src/routes/auth/organizations/activateOrganizationMembership.ts b/packages/api/src/routes/auth/organizations/activateOrganizationMembership.ts index 24c17b3..5f733c4 100644 --- a/packages/api/src/routes/auth/organizations/activateOrganizationMembership.ts +++ b/packages/api/src/routes/auth/organizations/activateOrganizationMembership.ts @@ -1,9 +1,9 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { updateOne } from "#/utilities/sql/updateOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { activateOrganizationMembershipRouteDefinition } from "@arrhes/metadata/routes" +import { authFactory } from "../../../factories/authFactory.js" +import { response } from "../../../utilities/response.js" +import { updateOne } from "../../../utilities/sql/updateOne.js" +import { bodyValidator } from "../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { activateOrganizationMembershipRouteDefinition } from "@arrhes/application-metadata/routes" import { and, eq } from "drizzle-orm" diff --git a/packages/api/src/routes/auth/organizations/addNewOrganization.ts b/packages/api/src/routes/auth/organizations/addNewOrganization.ts index 3325dcd..bcac0ff 100644 --- a/packages/api/src/routes/auth/organizations/addNewOrganization.ts +++ b/packages/api/src/routes/auth/organizations/addNewOrganization.ts @@ -1,10 +1,10 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { insertOne } from "#/utilities/sql/insertOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { addNewOrganizationRouteDefinition } from "@arrhes/metadata/routes" -import { generateId } from "@arrhes/metadata/utilities" +import { authFactory } from "../../../factories/authFactory.js" +import { response } from "../../../utilities/response.js" +import { insertOne } from "../../../utilities/sql/insertOne.js" +import { bodyValidator } from "../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { addNewOrganizationRouteDefinition } from "@arrhes/application-metadata/routes" +import { generateId } from "@arrhes/application-metadata/utilities" export const addNewOrganizationRoute = authFactory.createApp() diff --git a/packages/api/src/routes/auth/organizations/getAllMyOrganizations.ts b/packages/api/src/routes/auth/organizations/getAllMyOrganizations.ts index 743674a..592c449 100644 --- a/packages/api/src/routes/auth/organizations/getAllMyOrganizations.ts +++ b/packages/api/src/routes/auth/organizations/getAllMyOrganizations.ts @@ -1,7 +1,7 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { getAllMyOrganizationsRouteDefinition } from "@arrhes/metadata/routes" +import { authFactory } from "../../../factories/authFactory.js" +import { response } from "../../../utilities/response.js" +import { bodyValidator } from "../../../validators/bodyValidator.js" +import { getAllMyOrganizationsRouteDefinition } from "@arrhes/application-metadata/routes" import { and, eq } from "drizzle-orm" diff --git a/packages/api/src/routes/auth/organizations/organizationsRoutes.ts b/packages/api/src/routes/auth/organizations/organizationsRoutes.ts index bda0010..2e33351 100644 --- a/packages/api/src/routes/auth/organizations/organizationsRoutes.ts +++ b/packages/api/src/routes/auth/organizations/organizationsRoutes.ts @@ -1,7 +1,7 @@ -import { $idOrganizationRoutes } from "#/routes/auth/organizations/$idOrganization/$idOrganizationRoutes.js" -import { activateOrganizationMembershipRoute } from "#/routes/auth/organizations/activateOrganizationMembership.js" -import { addNewOrganizationRoute } from "#/routes/auth/organizations/addNewOrganization.js" -import { getAllMyOrganizationsRoute } from "#/routes/auth/organizations/getAllMyOrganizations.js" +import { $idOrganizationRoutes } from "../../../routes/auth/organizations/$idOrganization/$idOrganizationRoutes.js" +import { activateOrganizationMembershipRoute } from "../../../routes/auth/organizations/activateOrganizationMembership.js" +import { addNewOrganizationRoute } from "../../../routes/auth/organizations/addNewOrganization.js" +import { getAllMyOrganizationsRoute } from "../../../routes/auth/organizations/getAllMyOrganizations.js" export const organizationsRoutes = [ diff --git a/packages/api/src/routes/auth/settings/activateUser.ts b/packages/api/src/routes/auth/settings/activateUser.ts index 30d790c..78434ef 100644 --- a/packages/api/src/routes/auth/settings/activateUser.ts +++ b/packages/api/src/routes/auth/settings/activateUser.ts @@ -1,10 +1,10 @@ -import { authFactory } from "#/factories/authFactory.js" -import { Exception } from "#/utilities/exception.js" -import { response } from "#/utilities/response.js" -import { updateOne } from "#/utilities/sql/updateOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { activateUserRouteDefinition } from "@arrhes/metadata/routes" +import { authFactory } from "../../../factories/authFactory.js" +import { Exception } from "../../../utilities/exception.js" +import { response } from "../../../utilities/response.js" +import { updateOne } from "../../../utilities/sql/updateOne.js" +import { bodyValidator } from "../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { activateUserRouteDefinition } from "@arrhes/application-metadata/routes" import { eq } from "drizzle-orm" export const activateUserRoute = authFactory.createApp() diff --git a/packages/api/src/routes/auth/settings/readUserSession.ts b/packages/api/src/routes/auth/settings/readUserSession.ts index c9fa04a..c4542d0 100644 --- a/packages/api/src/routes/auth/settings/readUserSession.ts +++ b/packages/api/src/routes/auth/settings/readUserSession.ts @@ -1,7 +1,7 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { readUserSessionRouteDefinition } from "@arrhes/metadata/routes" +import { authFactory } from "../../../factories/authFactory.js" +import { response } from "../../../utilities/response.js" +import { bodyValidator } from "../../../validators/bodyValidator.js" +import { readUserSessionRouteDefinition } from "@arrhes/application-metadata/routes" export const readUserSessionRoute = authFactory.createApp() diff --git a/packages/api/src/routes/auth/settings/settingsRoutes.ts b/packages/api/src/routes/auth/settings/settingsRoutes.ts index a0d2ad1..5e7c9cc 100644 --- a/packages/api/src/routes/auth/settings/settingsRoutes.ts +++ b/packages/api/src/routes/auth/settings/settingsRoutes.ts @@ -1,9 +1,9 @@ -import { activateUserRoute } from "#/routes/auth/settings/activateUser.js" -import { readUserSessionRoute } from "#/routes/auth/settings/readUserSession.js" -import { updateUserRoute } from "#/routes/auth/settings/updateUser.js" -import { updateUserEmailRoute } from "#/routes/auth/settings/updateUserEmail.js" -import { updateUserPasswordRoute } from "#/routes/auth/settings/updateUserPassword.js" -import { validateUserEmailRoute } from "#/routes/auth/settings/validateUserEmail.js" +import { activateUserRoute } from "../../../routes/auth/settings/activateUser.js" +import { readUserSessionRoute } from "../../../routes/auth/settings/readUserSession.js" +import { updateUserRoute } from "../../../routes/auth/settings/updateUser.js" +import { updateUserEmailRoute } from "../../../routes/auth/settings/updateUserEmail.js" +import { updateUserPasswordRoute } from "../../../routes/auth/settings/updateUserPassword.js" +import { validateUserEmailRoute } from "../../../routes/auth/settings/validateUserEmail.js" export const settingsRoutes = [ diff --git a/packages/api/src/routes/auth/settings/updateUser.ts b/packages/api/src/routes/auth/settings/updateUser.ts index 74bb6c9..ad8673a 100644 --- a/packages/api/src/routes/auth/settings/updateUser.ts +++ b/packages/api/src/routes/auth/settings/updateUser.ts @@ -1,9 +1,9 @@ -import { authFactory } from "#/factories/authFactory.js" -import { response } from "#/utilities/response.js" -import { updateOne } from "#/utilities/sql/updateOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { updateUserRouteDefinition } from "@arrhes/metadata/routes" +import { authFactory } from "../../../factories/authFactory.js" +import { response } from "../../../utilities/response.js" +import { updateOne } from "../../../utilities/sql/updateOne.js" +import { bodyValidator } from "../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { updateUserRouteDefinition } from "@arrhes/application-metadata/routes" import { eq } from "drizzle-orm" diff --git a/packages/api/src/routes/auth/settings/updateUserEmail.ts b/packages/api/src/routes/auth/settings/updateUserEmail.ts index 055dac6..11a9b9d 100644 --- a/packages/api/src/routes/auth/settings/updateUserEmail.ts +++ b/packages/api/src/routes/auth/settings/updateUserEmail.ts @@ -1,11 +1,11 @@ -import { authFactory } from "#/factories/authFactory.js" -import { Exception } from "#/utilities/exception.js" -import { generateVerificationToken } from "#/utilities/generateVerificationToken.js" -import { response } from "#/utilities/response.js" -import { updateOne } from "#/utilities/sql/updateOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { updateUserEmailRouteDefinition } from "@arrhes/metadata/routes" +import { authFactory } from "../../../factories/authFactory.js" +import { Exception } from "../../../utilities/exception.js" +import { generateVerificationToken } from "../../../utilities/generateVerificationToken.js" +import { response } from "../../../utilities/response.js" +import { updateOne } from "../../../utilities/sql/updateOne.js" +import { bodyValidator } from "../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { updateUserEmailRouteDefinition } from "@arrhes/application-metadata/routes" import { pbkdf2Sync } from "crypto" import { eq } from "drizzle-orm" diff --git a/packages/api/src/routes/auth/settings/updateUserPassword.ts b/packages/api/src/routes/auth/settings/updateUserPassword.ts index 87f91ef..b09640b 100644 --- a/packages/api/src/routes/auth/settings/updateUserPassword.ts +++ b/packages/api/src/routes/auth/settings/updateUserPassword.ts @@ -1,10 +1,10 @@ -import { authFactory } from "#/factories/authFactory.js" -import { Exception } from "#/utilities/exception.js" -import { response } from "#/utilities/response.js" -import { updateOne } from "#/utilities/sql/updateOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { updateUserPasswordRouteDefinition } from "@arrhes/metadata/routes" +import { authFactory } from "../../../factories/authFactory.js" +import { Exception } from "../../../utilities/exception.js" +import { response } from "../../../utilities/response.js" +import { updateOne } from "../../../utilities/sql/updateOne.js" +import { bodyValidator } from "../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { updateUserPasswordRouteDefinition } from "@arrhes/application-metadata/routes" import { pbkdf2Sync } from "crypto" import { eq } from "drizzle-orm" diff --git a/packages/api/src/routes/auth/settings/validateUserEmail.ts b/packages/api/src/routes/auth/settings/validateUserEmail.ts index bcf46f3..dfa41f3 100644 --- a/packages/api/src/routes/auth/settings/validateUserEmail.ts +++ b/packages/api/src/routes/auth/settings/validateUserEmail.ts @@ -1,10 +1,10 @@ -import { authFactory } from "#/factories/authFactory.js" -import { Exception } from "#/utilities/exception.js" -import { response } from "#/utilities/response.js" -import { updateOne } from "#/utilities/sql/updateOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { validateUserEmailRouteDefinition } from "@arrhes/metadata/routes" +import { authFactory } from "../../../factories/authFactory.js" +import { Exception } from "../../../utilities/exception.js" +import { response } from "../../../utilities/response.js" +import { updateOne } from "../../../utilities/sql/updateOne.js" +import { bodyValidator } from "../../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { validateUserEmailRouteDefinition } from "@arrhes/application-metadata/routes" import { eq } from "drizzle-orm" diff --git a/packages/api/src/routes/auth/support/sendSupportMessage.ts b/packages/api/src/routes/auth/support/sendSupportMessage.ts index b5c86be..863b9b6 100644 --- a/packages/api/src/routes/auth/support/sendSupportMessage.ts +++ b/packages/api/src/routes/auth/support/sendSupportMessage.ts @@ -1,9 +1,9 @@ -import { authFactory } from "#/factories/authFactory.js" -import { sendEmail } from "#/utilities/email/sendEmail.js" -import { supportTemplate } from "#/utilities/email/templates/support.js" -import { response } from "#/utilities/response.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { sendSupportMessageRouteDefinition } from "@arrhes/metadata/routes" +import { authFactory } from "../../../factories/authFactory.js" +import { sendEmail } from "../../../utilities/email/sendEmail.js" +import { supportTemplate } from "../../../utilities/email/templates/support.js" +import { response } from "../../../utilities/response.js" +import { bodyValidator } from "../../../validators/bodyValidator.js" +import { sendSupportMessageRouteDefinition } from "@arrhes/application-metadata/routes" export const sendSupportMessageRoute = authFactory.createApp() diff --git a/packages/api/src/routes/auth/support/supportRoutes.ts b/packages/api/src/routes/auth/support/supportRoutes.ts index 10fbcf7..ab26ccd 100644 --- a/packages/api/src/routes/auth/support/supportRoutes.ts +++ b/packages/api/src/routes/auth/support/supportRoutes.ts @@ -1,4 +1,4 @@ -import { sendSupportMessageRoute } from "#/routes/auth/support/sendSupportMessage.js" +import { sendSupportMessageRoute } from "../../../routes/auth/support/sendSupportMessage.js" export const supportRoutes = [ diff --git a/packages/api/src/routes/public/publicRoute.ts b/packages/api/src/routes/public/publicRoute.ts index e6c74d4..5d43cbc 100644 --- a/packages/api/src/routes/public/publicRoute.ts +++ b/packages/api/src/routes/public/publicRoute.ts @@ -1,12 +1,12 @@ -import { publicFactory } from "#/factories/publicFactory.js" -import { sendMagicLinkRoute } from "#/routes/public/sendMagicLink.js" -import { signInRoute } from "#/routes/public/signIn.js" -import { signOutRoute } from "#/routes/public/signOut.js" -import { signUpRoute } from "#/routes/public/signUp.js" - - -export const publicRoute = publicFactory.createApp() - .route("/", signInRoute) - .route("/", signUpRoute) - .route("/", signOutRoute) - .route("/", sendMagicLinkRoute) +import { publicFactory } from "../../factories/publicFactory.js" +import { sendMagicLinkRoute } from "../../routes/public/sendMagicLink.js" +import { signInRoute } from "../../routes/public/signIn.js" +import { signOutRoute } from "../../routes/public/signOut.js" +import { signUpRoute } from "../../routes/public/signUp.js" + + +export const publicRoute = publicFactory.createApp() + .route("/", signInRoute) + .route("/", signUpRoute) + .route("/", signOutRoute) + .route("/", sendMagicLinkRoute) diff --git a/packages/api/src/routes/public/sendMagicLink.ts b/packages/api/src/routes/public/sendMagicLink.ts index 8550509..9638bd0 100644 --- a/packages/api/src/routes/public/sendMagicLink.ts +++ b/packages/api/src/routes/public/sendMagicLink.ts @@ -1,32 +1,32 @@ -import { publicFactory } from "#/factories/publicFactory.js" -import { response } from "#/utilities/response.js" -import { selectOne } from "#/utilities/sql/selectOne.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { sendMagicLinkRouteDefinition } from "@arrhes/metadata/routes" -import { eq } from "drizzle-orm" - - -export const sendMagicLinkRoute = publicFactory.createApp() - .post( - sendMagicLinkRouteDefinition.path, - bodyValidator(sendMagicLinkRouteDefinition.schemas.body), - async (c) => { - const body = c.req.valid("json") - - const user = await selectOne({ - database: c.var.clients.sql, - table: models.user, - where: (table) => ( - eq(table.email, body.email.trim().toLowerCase()) - ) - }) - - return response({ - context: c, - statusCode: 200, - schema: sendMagicLinkRouteDefinition.schemas.return, - data: {}, - }) - } +import { publicFactory } from "../../factories/publicFactory.js" +import { response } from "../../utilities/response.js" +import { selectOne } from "../../utilities/sql/selectOne.js" +import { bodyValidator } from "../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { sendMagicLinkRouteDefinition } from "@arrhes/application-metadata/routes" +import { eq } from "drizzle-orm" + + +export const sendMagicLinkRoute = publicFactory.createApp() + .post( + sendMagicLinkRouteDefinition.path, + bodyValidator(sendMagicLinkRouteDefinition.schemas.body), + async (c) => { + const body = c.req.valid("json") + + const user = await selectOne({ + database: c.var.clients.sql, + table: models.user, + where: (table) => ( + eq(table.email, body.email.trim().toLowerCase()) + ) + }) + + return response({ + context: c, + statusCode: 200, + schema: sendMagicLinkRouteDefinition.schemas.return, + data: {}, + }) + } ) \ No newline at end of file diff --git a/packages/api/src/routes/public/signIn.ts b/packages/api/src/routes/public/signIn.ts index 08c1b61..a2947a5 100644 --- a/packages/api/src/routes/public/signIn.ts +++ b/packages/api/src/routes/public/signIn.ts @@ -1,100 +1,99 @@ -import { publicFactory } from "#/factories/publicFactory.js" -import { serializeCookie } from "#/utilities/cookies/serializeCookie.js" -import { signString } from "#/utilities/cookies/signString.js" -import { Exception } from "#/utilities/exception.js" -import { getRemoteAddress } from "#/utilities/getRemoteAddress.js" -import { response } from "#/utilities/response.js" -import { insertOne } from "#/utilities/sql/insertOne.js" -import { selectOne } from "#/utilities/sql/selectOne.js" -import { cookiePrefix, userSessionCookieMaxAge } from "#/utilities/variables.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { signInRouteDefinition } from "@arrhes/metadata/routes" -import { generateId } from "@arrhes/metadata/utilities" -import { pbkdf2Sync } from "crypto" -import { eq } from "drizzle-orm" - - -export const signInRoute = publicFactory.createApp() - .post( - signInRouteDefinition.path, - bodyValidator(signInRouteDefinition.schemas.body), - async (c) => { - const body = c.req.valid("json") - - const user = await selectOne({ - database: c.var.clients.sql, - table: models.user, - where: (table) => ( - eq(table.email, body.email.trim().toLowerCase()) - ) - }) - - const passwordHash = pbkdf2Sync(body.password, user.passwordSalt, 128000, 64, "sha512").toString("hex") - if (passwordHash !== user.passwordHash) { - throw new Exception({ - statusCode: 400, - internalMessage: "Error signing in", - cause: "Password does not match the database one" - }) - } - - - // Store the session - const createUserSession = await insertOne({ - database: c.var.clients.sql, - table: models.userSession, - data: { - id: generateId(), - idUser: user.id, - isActive: true, - expiresAt: new Date(Date.now() + userSessionCookieMaxAge).toISOString(), - ip: getRemoteAddress({ context: c }), - createdAt: new Date().toISOString(), - lastUpdatedAt: null, - } - }) - - // Set cookies - c.res.headers.append( - "Set-Cookie", - serializeCookie({ - name: `${cookiePrefix}_${"id_user_session"}`, - value: signString({ - value: createUserSession.id, - secret: c.var.env.COOKIES_KEY, - }), - options: { - maxAge: userSessionCookieMaxAge, - httpOnly: true, - secure: true, - sameSite: "None", - domain: c.var.env.COOKIES_DOMAIN, - path: "/", - } - }) - ) - c.res.headers.append( - "Set-Cookie", - serializeCookie({ - name: `${cookiePrefix}_${"is_auth"}`, - value: String(true), - options: { - maxAge: userSessionCookieMaxAge, - httpOnly: false, - secure: true, - sameSite: "None", - domain: c.var.env.COOKIES_DOMAIN, - path: "/", - } - }) - ) - - return response({ - context: c, - statusCode: 200, - schema: signInRouteDefinition.schemas.return, - data: {}, - }) - } +import { publicFactory } from "../../factories/publicFactory.js" +import { serializeCookie } from "../../utilities/cookies/serializeCookie.js" +import { signString } from "../../utilities/cookies/signString.js" +import { Exception } from "../../utilities/exception.js" +import { getRemoteAddress } from "../../utilities/getRemoteAddress.js" +import { response } from "../../utilities/response.js" +import { insertOne } from "../../utilities/sql/insertOne.js" +import { selectOne } from "../../utilities/sql/selectOne.js" +import { cookiePrefix, getCookieSecurityOptions, userSessionCookieMaxAge } from "../../utilities/variables.js" +import { bodyValidator } from "../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { signInRouteDefinition } from "@arrhes/application-metadata/routes" +import { generateId } from "@arrhes/application-metadata/utilities" +import { pbkdf2Sync } from "crypto" +import { eq } from "drizzle-orm" + + +export const signInRoute = publicFactory.createApp() + .post( + signInRouteDefinition.path, + bodyValidator(signInRouteDefinition.schemas.body), + async (c) => { + const body = c.req.valid("json") + + const user = await selectOne({ + database: c.var.clients.sql, + table: models.user, + where: (table) => ( + eq(table.email, body.email.trim().toLowerCase()) + ) + }) + + const passwordHash = pbkdf2Sync(body.password, user.passwordSalt, 128000, 64, "sha512").toString("hex") + if (passwordHash !== user.passwordHash) { + throw new Exception({ + statusCode: 400, + internalMessage: "Error signing in", + cause: "Password does not match the database one" + }) + } + + + // Store the session + const createUserSession = await insertOne({ + database: c.var.clients.sql, + table: models.userSession, + data: { + id: generateId(), + idUser: user.id, + isActive: true, + expiresAt: new Date(Date.now() + userSessionCookieMaxAge).toISOString(), + ip: getRemoteAddress({ context: c }), + createdAt: new Date().toISOString(), + lastUpdatedAt: null, + } + }) + + // Set cookies + const cookieSecurity = getCookieSecurityOptions(c.var.env.ENV) + c.res.headers.append( + "Set-Cookie", + serializeCookie({ + name: `${cookiePrefix}_${"id_user_session"}`, + value: signString({ + value: createUserSession.id, + secret: c.var.env.COOKIES_KEY, + }), + options: { + maxAge: userSessionCookieMaxAge, + httpOnly: true, + ...cookieSecurity, + domain: c.var.env.COOKIES_DOMAIN, + path: "/", + } + }) + ) + c.res.headers.append( + "Set-Cookie", + serializeCookie({ + name: `${cookiePrefix}_${"is_auth"}`, + value: String(true), + options: { + maxAge: userSessionCookieMaxAge, + httpOnly: false, + ...cookieSecurity, + domain: c.var.env.COOKIES_DOMAIN, + path: "/", + } + }) + ) + + return response({ + context: c, + statusCode: 200, + schema: signInRouteDefinition.schemas.return, + data: {}, + }) + } ) \ No newline at end of file diff --git a/packages/api/src/routes/public/signOut.ts b/packages/api/src/routes/public/signOut.ts index 2af43c1..001dfc8 100644 --- a/packages/api/src/routes/public/signOut.ts +++ b/packages/api/src/routes/public/signOut.ts @@ -1,91 +1,90 @@ -import { publicFactory } from "#/factories/publicFactory.js" -import { parseCookies } from "#/utilities/cookies/parseCookies.js" -import { serializeCookie } from "#/utilities/cookies/serializeCookie.js" -import { unsignString } from "#/utilities/cookies/unsignString.js" -import { Exception } from "#/utilities/exception.js" -import { response } from "#/utilities/response.js" -import { updateOne } from "#/utilities/sql/updateOne.js" -import { cookiePrefix, userSessionCookieMaxAge } from "#/utilities/variables.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { signOutRouteDefinition } from "@arrhes/metadata/routes" -import { eq } from "drizzle-orm" - - -export const signOutRoute = publicFactory.createApp() - .post( - signOutRouteDefinition.path, - bodyValidator(signOutRouteDefinition.schemas.body), - async (c) => { - // const body = c.req.valid("json") - - try { - const idUserSession = unsignString({ - signedValue: parseCookies({ value: c.req.header("cookie") })[`${cookiePrefix}_${"id_user_session"}`], - secret: c.var.env.COOKIES_KEY, - }) - - if (idUserSession === undefined) { - throw new Exception({ - statusCode: 401, - internalMessage: "Invalid session", - cause: "idUserSession not found in signed cookie" - }) - } - - await updateOne({ - database: c.var.clients.sql, - table: models.userSession, - data: { - lastUpdatedAt: new Date().toISOString(), - isActive: false, - }, - where: (table) => ( - eq(table.id, idUserSession) - ) - }) - } - catch (erro: unknown) { - // do nothing - } - - - c.res.headers.append( - "Set-Cookie", - serializeCookie({ - name: `${cookiePrefix}_${"id_user_session"}`, - value: "", - options: { - maxAge: userSessionCookieMaxAge, - httpOnly: true, - secure: true, - sameSite: "None", - domain: c.var.env.COOKIES_DOMAIN, - path: "/", - } - }) - ) - c.res.headers.append( - "Set-Cookie", - serializeCookie({ - name: `${cookiePrefix}_${"is_auth"}`, - value: String(false), - options: { - maxAge: userSessionCookieMaxAge, - httpOnly: false, - secure: true, - sameSite: "None", - domain: c.var.env.COOKIES_DOMAIN, - path: "/", - } - }) - ) - - return response({ - context: c, - statusCode: 200, - schema: signOutRouteDefinition.schemas.return, - data: {}, - }) - } +import { publicFactory } from "../../factories/publicFactory.js" +import { parseCookies } from "../../utilities/cookies/parseCookies.js" +import { serializeCookie } from "../../utilities/cookies/serializeCookie.js" +import { unsignString } from "../../utilities/cookies/unsignString.js" +import { Exception } from "../../utilities/exception.js" +import { response } from "../../utilities/response.js" +import { updateOne } from "../../utilities/sql/updateOne.js" +import { cookiePrefix, getCookieSecurityOptions, userSessionCookieMaxAge } from "../../utilities/variables.js" +import { bodyValidator } from "../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { signOutRouteDefinition } from "@arrhes/application-metadata/routes" +import { eq } from "drizzle-orm" + + +export const signOutRoute = publicFactory.createApp() + .post( + signOutRouteDefinition.path, + bodyValidator(signOutRouteDefinition.schemas.body), + async (c) => { + // const body = c.req.valid("json") + + try { + const idUserSession = unsignString({ + signedValue: parseCookies({ value: c.req.header("cookie") })[`${cookiePrefix}_${"id_user_session"}`], + secret: c.var.env.COOKIES_KEY, + }) + + if (idUserSession === undefined) { + throw new Exception({ + statusCode: 401, + internalMessage: "Invalid session", + cause: "idUserSession not found in signed cookie" + }) + } + + await updateOne({ + database: c.var.clients.sql, + table: models.userSession, + data: { + lastUpdatedAt: new Date().toISOString(), + isActive: false, + }, + where: (table) => ( + eq(table.id, idUserSession) + ) + }) + } + catch (erro: unknown) { + // do nothing + } + + + const cookieSecurity = getCookieSecurityOptions(c.var.env.ENV) + c.res.headers.append( + "Set-Cookie", + serializeCookie({ + name: `${cookiePrefix}_${"id_user_session"}`, + value: "", + options: { + maxAge: userSessionCookieMaxAge, + httpOnly: true, + ...cookieSecurity, + domain: c.var.env.COOKIES_DOMAIN, + path: "/", + } + }) + ) + c.res.headers.append( + "Set-Cookie", + serializeCookie({ + name: `${cookiePrefix}_${"is_auth"}`, + value: String(false), + options: { + maxAge: userSessionCookieMaxAge, + httpOnly: false, + ...cookieSecurity, + domain: c.var.env.COOKIES_DOMAIN, + path: "/", + } + }) + ) + + return response({ + context: c, + statusCode: 200, + schema: signOutRouteDefinition.schemas.return, + data: {}, + }) + } ) \ No newline at end of file diff --git a/packages/api/src/routes/public/signUp.ts b/packages/api/src/routes/public/signUp.ts index 6399668..8bbe862 100644 --- a/packages/api/src/routes/public/signUp.ts +++ b/packages/api/src/routes/public/signUp.ts @@ -1,125 +1,124 @@ -import { publicFactory } from "#/factories/publicFactory.js" -import { serializeCookie } from "#/utilities/cookies/serializeCookie.js" -import { signString } from "#/utilities/cookies/signString.js" -import { Exception } from "#/utilities/exception.js" -import { generateVerificationToken } from "#/utilities/generateVerificationToken.js" -import { getRemoteAddress } from "#/utilities/getRemoteAddress.js" -import { response } from "#/utilities/response.js" -import { insertOne } from "#/utilities/sql/insertOne.js" -import { cookiePrefix, userSessionCookieMaxAge } from "#/utilities/variables.js" -import { bodyValidator } from "#/validators/bodyValidator.js" -import { models } from "@arrhes/metadata/models" -import { signUpRouteDefinition } from "@arrhes/metadata/routes" -import { generateId } from "@arrhes/metadata/utilities" -import { pbkdf2Sync } from "crypto" - - -export const signUpRoute = publicFactory.createApp() - .post( - signUpRouteDefinition.path, - bodyValidator(signUpRouteDefinition.schemas.body), - async (c) => { - const body = c.req.valid("json") - - if (body.password !== body.passwordCheck) { - throw new Exception({ - statusCode: 400, - internalMessage: "Different passwords", - externalMessage: "Les mots de passe renseignés sont différents" - }) - } - - const createUserSession = await c.var.clients.sql.transaction(async (tx) => { - - const passwordSalt = generateId() - const passwordHash = pbkdf2Sync(body.password, passwordSalt, 128000, 64, "sha512").toString("hex") - - const createUser = await insertOne({ - database: tx, - table: models.user, - data: { - id: generateId(), - isActive: true, - alias: null, - email: body.email, - isEmailValidated: false, - emailToken: generateVerificationToken(), - emailTokenExpiresAt: new Date(new Date().getTime() + (60 * 60 * 1000)).toISOString(), - passwordHash: passwordHash, - passwordSalt: passwordSalt, - createdAt: new Date().toISOString(), - lastUpdatedAt: null, - } - }) - - // Store the session - const createUserSession = await insertOne({ - database: tx, - table: models.userSession, - data: { - id: generateId(), - idUser: createUser.id, - isActive: true, - expiresAt: new Date(Date.now() + userSessionCookieMaxAge).toISOString(), - ip: getRemoteAddress({ context: c }), - createdAt: new Date().toISOString(), - lastUpdatedAt: null, - } - }) - - return createUserSession - }) - - - // Set cookies - c.res.headers.append( - "Set-Cookie", - serializeCookie({ - name: `${cookiePrefix}_${"id_user_session"}`, - value: signString({ - value: createUserSession.id, - secret: c.var.env.COOKIES_KEY, - }), - options: { - maxAge: userSessionCookieMaxAge, - httpOnly: true, - secure: true, - sameSite: "None", - domain: c.var.env.COOKIES_DOMAIN, - path: "/", - } - }) - ) - c.res.headers.append( - "Set-Cookie", - serializeCookie({ - name: `${cookiePrefix}_${"is_auth"}`, - value: String(true), - options: { - maxAge: userSessionCookieMaxAge, - httpOnly: false, - secure: true, - sameSite: "None", - domain: c.var.env.COOKIES_DOMAIN, - path: "/", - } - }) - ) - - - // await sendEmail({ - // to: userResponse.email, - // subject: "Valider votre email", - // html: emailValidationTemplate({ - // url: `${urlApp}/services/email?id=${userResponse.id}&token=${userResponse.emailToken}`, - // }) - // }) - - return response({ - context: c, - statusCode: 200, - schema: signUpRouteDefinition.schemas.return, - data: {}, - }) - } +import { publicFactory } from "../../factories/publicFactory.js" +import { serializeCookie } from "../../utilities/cookies/serializeCookie.js" +import { signString } from "../../utilities/cookies/signString.js" +import { Exception } from "../../utilities/exception.js" +import { generateVerificationToken } from "../../utilities/generateVerificationToken.js" +import { getRemoteAddress } from "../../utilities/getRemoteAddress.js" +import { response } from "../../utilities/response.js" +import { insertOne } from "../../utilities/sql/insertOne.js" +import { cookiePrefix, getCookieSecurityOptions, userSessionCookieMaxAge } from "../../utilities/variables.js" +import { bodyValidator } from "../../validators/bodyValidator.js" +import { models } from "@arrhes/application-metadata/models" +import { signUpRouteDefinition } from "@arrhes/application-metadata/routes" +import { generateId } from "@arrhes/application-metadata/utilities" +import { pbkdf2Sync } from "crypto" + + +export const signUpRoute = publicFactory.createApp() + .post( + signUpRouteDefinition.path, + bodyValidator(signUpRouteDefinition.schemas.body), + async (c) => { + const body = c.req.valid("json") + + if (body.password !== body.passwordCheck) { + throw new Exception({ + statusCode: 400, + internalMessage: "Different passwords", + externalMessage: "Les mots de passe renseignés sont différents" + }) + } + + const createUserSession = await c.var.clients.sql.transaction(async (tx) => { + + const passwordSalt = generateId() + const passwordHash = pbkdf2Sync(body.password, passwordSalt, 128000, 64, "sha512").toString("hex") + + const createUser = await insertOne({ + database: tx, + table: models.user, + data: { + id: generateId(), + isActive: true, + alias: null, + email: body.email, + isEmailValidated: false, + emailToken: generateVerificationToken(), + emailTokenExpiresAt: new Date(new Date().getTime() + (60 * 60 * 1000)).toISOString(), + passwordHash: passwordHash, + passwordSalt: passwordSalt, + createdAt: new Date().toISOString(), + lastUpdatedAt: null, + } + }) + + // Store the session + const createUserSession = await insertOne({ + database: tx, + table: models.userSession, + data: { + id: generateId(), + idUser: createUser.id, + isActive: true, + expiresAt: new Date(Date.now() + userSessionCookieMaxAge).toISOString(), + ip: getRemoteAddress({ context: c }), + createdAt: new Date().toISOString(), + lastUpdatedAt: null, + } + }) + + return createUserSession + }) + + + // Set cookies + const cookieSecurity = getCookieSecurityOptions(c.var.env.ENV) + c.res.headers.append( + "Set-Cookie", + serializeCookie({ + name: `${cookiePrefix}_${"id_user_session"}`, + value: signString({ + value: createUserSession.id, + secret: c.var.env.COOKIES_KEY, + }), + options: { + maxAge: userSessionCookieMaxAge, + httpOnly: true, + ...cookieSecurity, + domain: c.var.env.COOKIES_DOMAIN, + path: "/", + } + }) + ) + c.res.headers.append( + "Set-Cookie", + serializeCookie({ + name: `${cookiePrefix}_${"is_auth"}`, + value: String(true), + options: { + maxAge: userSessionCookieMaxAge, + httpOnly: false, + ...cookieSecurity, + domain: c.var.env.COOKIES_DOMAIN, + path: "/", + } + }) + ) + + + // await sendEmail({ + // to: userResponse.email, + // subject: "Valider votre email", + // html: emailValidationTemplate({ + // url: `${urlApp}/services/email?id=${userResponse.id}&token=${userResponse.emailToken}`, + // }) + // }) + + return response({ + context: c, + statusCode: 200, + schema: signUpRouteDefinition.schemas.return, + data: {}, + }) + } ) \ No newline at end of file diff --git a/packages/api/src/routes/routes.ts b/packages/api/src/routes/routes.ts index 0295df0..0f5885e 100644 --- a/packages/api/src/routes/routes.ts +++ b/packages/api/src/routes/routes.ts @@ -1,8 +1,8 @@ -import { apiFactory } from "#/factories/apiFactory.js" -import { authRoute } from "#/routes/auth/authRoute.js" -import { publicRoute } from "#/routes/public/publicRoute.js" - - -export const routes = apiFactory.createApp() - .route("/", authRoute) - .route("/", publicRoute) +import { apiFactory } from "../factories/apiFactory.js" +import { authRoute } from "../routes/auth/authRoute.js" +import { publicRoute } from "../routes/public/publicRoute.js" + + +export const routes = apiFactory.createApp() + .route("/", authRoute) + .route("/", publicRoute) diff --git a/packages/api/src/server.ts b/packages/api/src/server.ts index 1e28abe..6fd5f5c 100644 --- a/packages/api/src/server.ts +++ b/packages/api/src/server.ts @@ -1,6 +1,6 @@ -import { api } from "#/api.js" -import { getClients } from "#/utilities/getClients.js" -import { getEnv } from "#/utilities/getEnv.js" +import { api } from "./api.js" +import { getClients } from "./utilities/getClients.js" +import { getEnv } from "./utilities/getEnv.js" import { createServer } from "http" @@ -51,7 +51,7 @@ async function startServer() { res.writeHead(response.status, { ...Object.fromEntries(response.headers), - "Set-Cookie": response.headers.get("Set-Cookie") ? response.headers.get("Set-Cookie")?.split(", ") : [] + "Set-Cookie": response.headers.getSetCookie() }) if (response.body) { diff --git a/packages/api/src/utilities/apiLog.ts b/packages/api/src/utilities/apiLog.ts index 3b271d1..42552ff 100644 --- a/packages/api/src/utilities/apiLog.ts +++ b/packages/api/src/utilities/apiLog.ts @@ -1,5 +1,5 @@ -import { getClients } from "#/utilities/getClients.js" -import { getEnv } from "#/utilities/getEnv.js" +import { getClients } from "../utilities/getClients.js" +import { getEnv } from "../utilities/getEnv.js" type ApiLog = { diff --git a/packages/api/src/utilities/cookies/parseCookies.ts b/packages/api/src/utilities/cookies/parseCookies.ts index 326a649..5d12bb4 100644 --- a/packages/api/src/utilities/cookies/parseCookies.ts +++ b/packages/api/src/utilities/cookies/parseCookies.ts @@ -1,4 +1,4 @@ -import { Exception } from "#/utilities/exception.js" +import { Exception } from "../../utilities/exception.js" export function parseCookies(parameters: { diff --git a/packages/api/src/utilities/cookies/signString.ts b/packages/api/src/utilities/cookies/signString.ts index 493f88f..3a521c1 100644 --- a/packages/api/src/utilities/cookies/signString.ts +++ b/packages/api/src/utilities/cookies/signString.ts @@ -1,4 +1,4 @@ -import { Exception } from "#/utilities/exception.js" +import { Exception } from "../../utilities/exception.js" import { createHmac } from "crypto" diff --git a/packages/api/src/utilities/cookies/unsignString.ts b/packages/api/src/utilities/cookies/unsignString.ts index e42dded..d95065c 100644 --- a/packages/api/src/utilities/cookies/unsignString.ts +++ b/packages/api/src/utilities/cookies/unsignString.ts @@ -1,5 +1,5 @@ -import { signString } from "#/utilities/cookies/signString.js" -import { Exception } from "#/utilities/exception.js" +import { signString } from "../../utilities/cookies/signString.js" +import { Exception } from "../../utilities/exception.js" import { timingSafeEqual } from "crypto" diff --git a/packages/api/src/utilities/email/sendEmail.ts b/packages/api/src/utilities/email/sendEmail.ts index de1473a..c1c3ea8 100644 --- a/packages/api/src/utilities/email/sendEmail.ts +++ b/packages/api/src/utilities/email/sendEmail.ts @@ -1,36 +1,36 @@ -import { Exception } from "#/utilities/exception.js" -import { getClients } from "#/utilities/getClients.js" -import { getEnv } from "#/utilities/getEnv.js" - - -export async function sendEmail(parameters: { - var: { - env: ReturnType - clients: Awaited> - }, - subject: string - from?: string - to: string | string[] - html: string - // attachments?: { - // content: Buffer | string | undefined - // filename: string - // }[] -}) { - try { - const response = await parameters.var.clients.email.sendMail(parameters) - - if (!response.accepted) { - throw new Exception({ - internalMessage: "Email not sent", - cause: response.rejected.toString() - }) - } - } - catch (error: unknown) { - throw new Exception({ - internalMessage: "Email not sent", - rawError: error - }) - } -} +import { Exception } from "../../utilities/exception.js" +import { getClients } from "../../utilities/getClients.js" +import { getEnv } from "../../utilities/getEnv.js" + + +export async function sendEmail(parameters: { + var: { + env: ReturnType + clients: Awaited> + }, + subject: string + from?: string + to: string | string[] + html: string + // attachments?: { + // content: Buffer | string | undefined + // filename: string + // }[] +}) { + try { + const response = await parameters.var.clients.email.sendMail(parameters) + + if (!response.accepted) { + throw new Exception({ + internalMessage: "Email not sent", + cause: response.rejected.toString() + }) + } + } + catch (error: unknown) { + throw new Exception({ + internalMessage: "Email not sent", + rawError: error + }) + } +} diff --git a/packages/api/src/utilities/email/templates/balanceSheetReport/balanceSheetAssets/balanceSheetAssetsReportItem.tsx b/packages/api/src/utilities/email/templates/balanceSheetReport/balanceSheetAssets/balanceSheetAssetsReportItem.tsx index d3b95ec..569176f 100644 --- a/packages/api/src/utilities/email/templates/balanceSheetReport/balanceSheetAssets/balanceSheetAssetsReportItem.tsx +++ b/packages/api/src/utilities/email/templates/balanceSheetReport/balanceSheetAssets/balanceSheetAssetsReportItem.tsx @@ -1,7 +1,7 @@ -import { BalanceSheetAssetsReportRow } from "#/utilities/email/templates/balanceSheetReport/balanceSheetAssets/balanceSheetAssetsReportRow.js" -import { getBalanceSheetChildren } from "#/utilities/email/templates/balanceSheetReport/getBalanceSheetChildren.js" -import { numberToRomanString } from "#/utilities/numberToRomanString.js" -import { returnedSchemas } from "@arrhes/metadata/schemas" +import { BalanceSheetAssetsReportRow } from "./balanceSheetAssetsReportRow.js" +import { getBalanceSheetChildren } from "../getBalanceSheetChildren.js" +import { numberToRomanString } from "../../../../numberToRomanString.js" +import { returnedSchemas } from "@arrhes/application-metadata/schemas" import { Style } from "hono/css" import { Fragment } from "hono/jsx/jsx-runtime" import * as v from "valibot" diff --git a/packages/api/src/utilities/email/templates/balanceSheetReport/balanceSheetAssets/balanceSheetAssetsReportRow.tsx b/packages/api/src/utilities/email/templates/balanceSheetReport/balanceSheetAssets/balanceSheetAssetsReportRow.tsx index 1301e15..f72797a 100644 --- a/packages/api/src/utilities/email/templates/balanceSheetReport/balanceSheetAssets/balanceSheetAssetsReportRow.tsx +++ b/packages/api/src/utilities/email/templates/balanceSheetReport/balanceSheetAssets/balanceSheetAssetsReportRow.tsx @@ -1,5 +1,5 @@ -import { PriceFormat } from "#/utilities/email/templates/components/price/priceFormat.js" -import { Table } from "#/utilities/email/templates/components/table/table.js" +import { PriceFormat } from "../../components/price/priceFormat.js" +import { Table } from "../../components/table/table.js" import { Style, css, cx } from "hono/css" import { Fragment } from "hono/jsx/jsx-runtime" diff --git a/packages/api/src/utilities/email/templates/balanceSheetReport/balanceSheetAssets/balanceSheetAssetsReportTable.tsx b/packages/api/src/utilities/email/templates/balanceSheetReport/balanceSheetAssets/balanceSheetAssetsReportTable.tsx index 9cbb925..32b7c7e 100644 --- a/packages/api/src/utilities/email/templates/balanceSheetReport/balanceSheetAssets/balanceSheetAssetsReportTable.tsx +++ b/packages/api/src/utilities/email/templates/balanceSheetReport/balanceSheetAssets/balanceSheetAssetsReportTable.tsx @@ -1,8 +1,8 @@ -import { BalanceSheetAssetsReportItem } from "#/utilities/email/templates/balanceSheetReport/balanceSheetAssets/balanceSheetAssetsReportItem.js" -import { BalanceSheetAssetsReportRow } from "#/utilities/email/templates/balanceSheetReport/balanceSheetAssets/balanceSheetAssetsReportRow.js" -import { getBalanceSheetChildren } from "#/utilities/email/templates/balanceSheetReport/getBalanceSheetChildren.js" -import { Table } from "#/utilities/email/templates/components/table/table.js" -import { returnedSchemas } from "@arrhes/metadata/schemas" +import { BalanceSheetAssetsReportItem } from "./balanceSheetAssetsReportItem.js" +import { BalanceSheetAssetsReportRow } from "./balanceSheetAssetsReportRow.js" +import { getBalanceSheetChildren } from "../getBalanceSheetChildren.js" +import { Table } from "../../components/table/table.js" +import { returnedSchemas } from "@arrhes/application-metadata/schemas" import { Style, css } from "hono/css" import { Fragment } from "hono/jsx/jsx-runtime" import * as v from "valibot" diff --git a/packages/api/src/utilities/email/templates/balanceSheetReport/balanceSheetLiabilities/balanceSheetLiabilitiesReportItem.tsx b/packages/api/src/utilities/email/templates/balanceSheetReport/balanceSheetLiabilities/balanceSheetLiabilitiesReportItem.tsx index c35bee3..6f18315 100644 --- a/packages/api/src/utilities/email/templates/balanceSheetReport/balanceSheetLiabilities/balanceSheetLiabilitiesReportItem.tsx +++ b/packages/api/src/utilities/email/templates/balanceSheetReport/balanceSheetLiabilities/balanceSheetLiabilitiesReportItem.tsx @@ -1,7 +1,7 @@ -import { BalanceSheetLiabilitiesReportRow } from "#/utilities/email/templates/balanceSheetReport/balanceSheetLiabilities/balanceSheetLiabilitiesReportRow.js" -import { getBalanceSheetChildren } from "#/utilities/email/templates/balanceSheetReport/getBalanceSheetChildren.js" -import { numberToRomanString } from "#/utilities/numberToRomanString.js" -import { returnedSchemas } from "@arrhes/metadata/schemas" +import { BalanceSheetLiabilitiesReportRow } from "./balanceSheetLiabilitiesReportRow.js" +import { getBalanceSheetChildren } from "../getBalanceSheetChildren.js" +import { numberToRomanString } from "../../../../numberToRomanString.js" +import { returnedSchemas } from "@arrhes/application-metadata/schemas" import { Style } from "hono/css" import { Fragment } from "hono/jsx/jsx-runtime" import * as v from "valibot" diff --git a/packages/api/src/utilities/email/templates/balanceSheetReport/balanceSheetLiabilities/balanceSheetLiabilitiesReportRow.tsx b/packages/api/src/utilities/email/templates/balanceSheetReport/balanceSheetLiabilities/balanceSheetLiabilitiesReportRow.tsx index 444cd82..cb00c74 100644 --- a/packages/api/src/utilities/email/templates/balanceSheetReport/balanceSheetLiabilities/balanceSheetLiabilitiesReportRow.tsx +++ b/packages/api/src/utilities/email/templates/balanceSheetReport/balanceSheetLiabilities/balanceSheetLiabilitiesReportRow.tsx @@ -1,5 +1,5 @@ -import { PriceFormat } from "#/utilities/email/templates/components/price/priceFormat.js" -import { Table } from "#/utilities/email/templates/components/table/table.js" +import { PriceFormat } from "../../components/price/priceFormat.js" +import { Table } from "../../components/table/table.js" import { Style, css, cx } from "hono/css" import { Fragment } from "hono/jsx/jsx-runtime" diff --git a/packages/api/src/utilities/email/templates/balanceSheetReport/balanceSheetLiabilities/balanceSheetLiabilitiesReportTable.tsx b/packages/api/src/utilities/email/templates/balanceSheetReport/balanceSheetLiabilities/balanceSheetLiabilitiesReportTable.tsx index 5ec4a73..4f2dd73 100644 --- a/packages/api/src/utilities/email/templates/balanceSheetReport/balanceSheetLiabilities/balanceSheetLiabilitiesReportTable.tsx +++ b/packages/api/src/utilities/email/templates/balanceSheetReport/balanceSheetLiabilities/balanceSheetLiabilitiesReportTable.tsx @@ -1,8 +1,8 @@ -import { BalanceSheetLiabilitiesReportItem } from "#/utilities/email/templates/balanceSheetReport/balanceSheetLiabilities/balanceSheetLiabilitiesReportItem.js" -import { BalanceSheetLiabilitiesReportRow } from "#/utilities/email/templates/balanceSheetReport/balanceSheetLiabilities/balanceSheetLiabilitiesReportRow.js" -import { getBalanceSheetChildren } from "#/utilities/email/templates/balanceSheetReport/getBalanceSheetChildren.js" -import { Table } from "#/utilities/email/templates/components/table/table.js" -import { returnedSchemas } from "@arrhes/metadata/schemas" +import { BalanceSheetLiabilitiesReportItem } from "./balanceSheetLiabilitiesReportItem.js" +import { BalanceSheetLiabilitiesReportRow } from "./balanceSheetLiabilitiesReportRow.js" +import { getBalanceSheetChildren } from "../getBalanceSheetChildren.js" +import { Table } from "../../components/table/table.js" +import { returnedSchemas } from "@arrhes/application-metadata/schemas" import { Style, css } from "hono/css" import { Fragment } from "hono/jsx/jsx-runtime" import * as v from "valibot" diff --git a/packages/api/src/utilities/email/templates/balanceSheetReport/balanceSheetReport.tsx b/packages/api/src/utilities/email/templates/balanceSheetReport/balanceSheetReport.tsx index 80f7fb4..c837dc0 100644 --- a/packages/api/src/utilities/email/templates/balanceSheetReport/balanceSheetReport.tsx +++ b/packages/api/src/utilities/email/templates/balanceSheetReport/balanceSheetReport.tsx @@ -1,6 +1,6 @@ -import { BalanceSheetAssetsReportTable } from "#/utilities/email/templates/balanceSheetReport/balanceSheetAssets/balanceSheetAssetsReportTable.js" -import { BalanceSheetLiabilitiesReportTable } from "#/utilities/email/templates/balanceSheetReport/balanceSheetLiabilities/balanceSheetLiabilitiesReportTable.js" -import { returnedSchemas } from "@arrhes/metadata/schemas" +import { BalanceSheetAssetsReportTable } from "./balanceSheetAssets/balanceSheetAssetsReportTable.js" +import { BalanceSheetLiabilitiesReportTable } from "./balanceSheetLiabilities/balanceSheetLiabilitiesReportTable.js" +import { returnedSchemas } from "@arrhes/application-metadata/schemas" import { Style, css } from "hono/css" import * as v from "valibot" diff --git a/packages/api/src/utilities/email/templates/balanceSheetReport/getBalanceSheetChildren.tsx b/packages/api/src/utilities/email/templates/balanceSheetReport/getBalanceSheetChildren.tsx index 1b08bd5..8a523cf 100644 --- a/packages/api/src/utilities/email/templates/balanceSheetReport/getBalanceSheetChildren.tsx +++ b/packages/api/src/utilities/email/templates/balanceSheetReport/getBalanceSheetChildren.tsx @@ -1,4 +1,4 @@ -import { returnedSchemas } from "@arrhes/metadata/schemas" +import { returnedSchemas } from "@arrhes/application-metadata/schemas" import * as v from "valibot" diff --git a/packages/api/src/utilities/email/templates/incomeStatementReport/getIncomeStatementChildren.tsx b/packages/api/src/utilities/email/templates/incomeStatementReport/getIncomeStatementChildren.tsx index 5fc1be8..aa9e1a3 100644 --- a/packages/api/src/utilities/email/templates/incomeStatementReport/getIncomeStatementChildren.tsx +++ b/packages/api/src/utilities/email/templates/incomeStatementReport/getIncomeStatementChildren.tsx @@ -1,4 +1,4 @@ -import { returnedSchemas } from "@arrhes/metadata/schemas" +import { returnedSchemas } from "@arrhes/application-metadata/schemas" import * as v from "valibot" diff --git a/packages/api/src/utilities/email/templates/incomeStatementReport/incomeStatementReport.tsx b/packages/api/src/utilities/email/templates/incomeStatementReport/incomeStatementReport.tsx index f6a7085..f8a124b 100644 --- a/packages/api/src/utilities/email/templates/incomeStatementReport/incomeStatementReport.tsx +++ b/packages/api/src/utilities/email/templates/incomeStatementReport/incomeStatementReport.tsx @@ -1,5 +1,5 @@ -import { IncomeStatementsReportTable } from "#/utilities/email/templates/incomeStatementReport/incomeStatementsReportTable.js" -import { returnedSchemas } from "@arrhes/metadata/schemas" +import { IncomeStatementsReportTable } from "./incomeStatementsReportTable.js" +import { returnedSchemas } from "@arrhes/application-metadata/schemas" import { Style, css } from "hono/css" import * as v from "valibot" diff --git a/packages/api/src/utilities/email/templates/incomeStatementReport/incomeStatementReportItem.tsx b/packages/api/src/utilities/email/templates/incomeStatementReport/incomeStatementReportItem.tsx index 5555815..467f783 100644 --- a/packages/api/src/utilities/email/templates/incomeStatementReport/incomeStatementReportItem.tsx +++ b/packages/api/src/utilities/email/templates/incomeStatementReport/incomeStatementReportItem.tsx @@ -1,7 +1,7 @@ -import { getIncomeStatementChildren } from "#/utilities/email/templates/incomeStatementReport/getIncomeStatementChildren.js" -import { IncomeStatementReportRow } from "#/utilities/email/templates/incomeStatementReport/incomeStatementReportRow.js" -import { numberToRomanString } from "#/utilities/numberToRomanString.js" -import { returnedSchemas } from "@arrhes/metadata/schemas" +import { getIncomeStatementChildren } from "./getIncomeStatementChildren.js" +import { IncomeStatementReportRow } from "./incomeStatementReportRow.js" +import { numberToRomanString } from "../../../numberToRomanString.js" +import { returnedSchemas } from "@arrhes/application-metadata/schemas" import { Fragment } from "hono/jsx/jsx-runtime" import * as v from "valibot" diff --git a/packages/api/src/utilities/email/templates/incomeStatementReport/incomeStatementReportRow.tsx b/packages/api/src/utilities/email/templates/incomeStatementReport/incomeStatementReportRow.tsx index b3b795f..5f0f737 100644 --- a/packages/api/src/utilities/email/templates/incomeStatementReport/incomeStatementReportRow.tsx +++ b/packages/api/src/utilities/email/templates/incomeStatementReport/incomeStatementReportRow.tsx @@ -1,5 +1,5 @@ -import { PriceFormat } from "#/utilities/email/templates/components/price/priceFormat.js" -import { Table } from "#/utilities/email/templates/components/table/table.js" +import { PriceFormat } from "../components/price/priceFormat.js" +import { Table } from "../components/table/table.js" import { css, cx, Style } from "hono/css" import { Fragment } from "hono/jsx/jsx-runtime" diff --git a/packages/api/src/utilities/email/templates/incomeStatementReport/incomeStatementsReportTable.tsx b/packages/api/src/utilities/email/templates/incomeStatementReport/incomeStatementsReportTable.tsx index b3c0694..3fe9766 100644 --- a/packages/api/src/utilities/email/templates/incomeStatementReport/incomeStatementsReportTable.tsx +++ b/packages/api/src/utilities/email/templates/incomeStatementReport/incomeStatementsReportTable.tsx @@ -1,9 +1,9 @@ -import { PriceFormat } from "#/utilities/email/templates/components/price/priceFormat.js" -import { Table } from "#/utilities/email/templates/components/table/table.js" -import { getIncomeStatementChildren } from "#/utilities/email/templates/incomeStatementReport/getIncomeStatementChildren.js" -import { IncomeStatementReportItem } from "#/utilities/email/templates/incomeStatementReport/incomeStatementReportItem.js" -import { numberToRomanString } from "#/utilities/numberToRomanString.js" -import { returnedSchemas } from "@arrhes/metadata/schemas" +import { PriceFormat } from "../components/price/priceFormat.js" +import { Table } from "../components/table/table.js" +import { getIncomeStatementChildren } from "./getIncomeStatementChildren.js" +import { IncomeStatementReportItem } from "./incomeStatementReportItem.js" +import { numberToRomanString } from "../../../numberToRomanString.js" +import { returnedSchemas } from "@arrhes/application-metadata/schemas" import { css } from "hono/css" import * as v from "valibot" diff --git a/packages/api/src/utilities/getClients.ts b/packages/api/src/utilities/getClients.ts index 4678a0a..23d3338 100644 --- a/packages/api/src/utilities/getClients.ts +++ b/packages/api/src/utilities/getClients.ts @@ -1,7 +1,7 @@ -import { emailClient } from "#/clients/emailClient.js" -import { sqlClient } from "#/clients/sqlClient.js" -import { storageClient } from "#/clients/storageClient.js" -import { getEnv } from "#/utilities/getEnv.js" +import { emailClient } from "../clients/emailClient.js" +import { sqlClient } from "../clients/sqlClient.js" +import { storageClient } from "../clients/storageClient.js" +import { getEnv } from "../utilities/getEnv.js" export async function getClients(env: ReturnType) { diff --git a/packages/api/src/utilities/getEnv.ts b/packages/api/src/utilities/getEnv.ts index 2b80264..303a135 100644 --- a/packages/api/src/utilities/getEnv.ts +++ b/packages/api/src/utilities/getEnv.ts @@ -1,45 +1,45 @@ -import { validate } from "#/utilities/validate.js" -import * as v from "valibot" - - -enum Env { - development = "development", - production = "production" -} - -const envSchema = v.object({ - ENV: v.enum_(Env), - VERBOSE: v.picklist(["true", "false"]), - PORT: v.string(), - - CORS_ORIGIN: v.string(), - COOKIES_DOMAIN: v.string(), - COOKIES_KEY: v.string(), - - API_BASE_URL: v.string(), - PLATFORM_BASE_URL: v.string(), - WEBSITE_BASE_URL: v.string(), - - SQL_DATABASE_URL: v.string(), - - STORAGE_ENDPOINT: v.string(), - STORAGE_NAME: v.string(), - STORAGE_ACCESS_KEY: v.string(), - STORAGE_SECRET_KEY: v.string(), - - EMAIL_ENDPOINT: v.string(), - EMAIL_USER: v.string(), - EMAIL_PASSWORD: v.string(), -}) - - -export function getEnv() { - const parsedEnv = validate({ - schema: envSchema, - // @ts-ignore - data: process.env, - message: "Missing environment variables", - }) - - return parsedEnv -} +import { validate } from "../utilities/validate.js" +import * as v from "valibot" + + +enum Env { + development = "development", + production = "production" +} + +const envSchema = v.object({ + ENV: v.enum_(Env), + VERBOSE: v.picklist(["true", "false"]), + PORT: v.string(), + + CORS_ORIGIN: v.string(), + COOKIES_DOMAIN: v.string(), + COOKIES_KEY: v.string(), + + API_BASE_URL: v.string(), + PLATFORM_BASE_URL: v.string(), + WEBSITE_BASE_URL: v.string(), + + SQL_DATABASE_URL: v.string(), + + STORAGE_ENDPOINT: v.string(), + STORAGE_BUCKET_NAME: v.string(), + STORAGE_ACCESS_KEY: v.string(), + STORAGE_SECRET_KEY: v.string(), + + EMAIL_ENDPOINT: v.string(), + EMAIL_USER: v.string(), + EMAIL_PASSWORD: v.string(), +}) + + +export function getEnv() { + const parsedEnv = validate({ + schema: envSchema, + // @ts-ignore + data: process.env, + message: "Missing environment variables", + }) + + return parsedEnv +} diff --git a/packages/api/src/utilities/response.ts b/packages/api/src/utilities/response.ts index 0e2c4b5..b07163c 100644 --- a/packages/api/src/utilities/response.ts +++ b/packages/api/src/utilities/response.ts @@ -1,8 +1,8 @@ -import { ApiEnv } from "#/factories/apiFactory.js" -import { AuthEnv } from "#/factories/authFactory.js" -import { PublicEnv } from "#/factories/publicFactory.js" -import { validate } from "#/utilities/validate.js" -import { routeDefinition } from "@arrhes/metadata/utilities" +import { ApiEnv } from "../factories/apiFactory.js" +import { AuthEnv } from "../factories/authFactory.js" +import { PublicEnv } from "../factories/publicFactory.js" +import { validate } from "../utilities/validate.js" +import { routeDefinition } from "@arrhes/application-metadata/utilities" import { Context } from "hono" import { ContentfulStatusCode } from "hono/utils/http-status" import * as v from "valibot" diff --git a/packages/api/src/utilities/safeParseJSON.ts b/packages/api/src/utilities/safeParseJSON.ts index 8c81e2b..18a302a 100644 --- a/packages/api/src/utilities/safeParseJSON.ts +++ b/packages/api/src/utilities/safeParseJSON.ts @@ -1,5 +1,5 @@ -import { completeStringifiedJSON } from "#/utilities/completeStringifiedJSON.js" -import { Exception } from "#/utilities/exception.js" +import { completeStringifiedJSON } from "../utilities/completeStringifiedJSON.js" +import { Exception } from "../utilities/exception.js" export function safeParseJSON(parameters: { diff --git a/packages/api/src/utilities/sql/deleteMany.ts b/packages/api/src/utilities/sql/deleteMany.ts index c65a0f6..4123cea 100644 --- a/packages/api/src/utilities/sql/deleteMany.ts +++ b/packages/api/src/utilities/sql/deleteMany.ts @@ -1,5 +1,5 @@ -import { sqlClient } from "#/clients/sqlClient.js" -import { Exception } from "#/utilities/exception.js" +import { sqlClient } from "../../clients/sqlClient.js" +import { Exception } from "../../utilities/exception.js" import { SQL, TableConfig } from "drizzle-orm" import { PgTable } from "drizzle-orm/pg-core" diff --git a/packages/api/src/utilities/sql/deleteOne.ts b/packages/api/src/utilities/sql/deleteOne.ts index d43ee24..2d3579c 100644 --- a/packages/api/src/utilities/sql/deleteOne.ts +++ b/packages/api/src/utilities/sql/deleteOne.ts @@ -1,5 +1,5 @@ -import { sqlClient } from "#/clients/sqlClient.js" -import { Exception } from "#/utilities/exception.js" +import { sqlClient } from "../../clients/sqlClient.js" +import { Exception } from "../../utilities/exception.js" import { SQL, TableConfig } from "drizzle-orm" import { PgTable } from "drizzle-orm/pg-core" diff --git a/packages/api/src/utilities/sql/insertMany.ts b/packages/api/src/utilities/sql/insertMany.ts index 3d77d0b..2ccb24e 100644 --- a/packages/api/src/utilities/sql/insertMany.ts +++ b/packages/api/src/utilities/sql/insertMany.ts @@ -1,5 +1,5 @@ -import { sqlClient } from "#/clients/sqlClient.js" -import { Exception } from "#/utilities/exception.js" +import { sqlClient } from "../../clients/sqlClient.js" +import { Exception } from "../../utilities/exception.js" import { PgInsertValue, PgTable, TableConfig } from "drizzle-orm/pg-core" diff --git a/packages/api/src/utilities/sql/insertOne.ts b/packages/api/src/utilities/sql/insertOne.ts index c9f1708..5a09ab0 100644 --- a/packages/api/src/utilities/sql/insertOne.ts +++ b/packages/api/src/utilities/sql/insertOne.ts @@ -1,5 +1,5 @@ -import { sqlClient } from "#/clients/sqlClient.js" -import { Exception } from "#/utilities/exception.js" +import { sqlClient } from "../../clients/sqlClient.js" +import { Exception } from "../../utilities/exception.js" import { TableConfig } from "drizzle-orm" import { PgInsertValue, PgTable } from "drizzle-orm/pg-core" diff --git a/packages/api/src/utilities/sql/selectMany.ts b/packages/api/src/utilities/sql/selectMany.ts index 13b27b8..e7797d2 100644 --- a/packages/api/src/utilities/sql/selectMany.ts +++ b/packages/api/src/utilities/sql/selectMany.ts @@ -1,5 +1,5 @@ -import { sqlClient } from "#/clients/sqlClient.js" -import { Exception } from "#/utilities/exception.js" +import { sqlClient } from "../../clients/sqlClient.js" +import { Exception } from "../../utilities/exception.js" import { SQL, TableConfig } from "drizzle-orm" import { PgTable } from "drizzle-orm/pg-core" diff --git a/packages/api/src/utilities/sql/selectOne.ts b/packages/api/src/utilities/sql/selectOne.ts index cd621da..e66c65c 100644 --- a/packages/api/src/utilities/sql/selectOne.ts +++ b/packages/api/src/utilities/sql/selectOne.ts @@ -1,5 +1,5 @@ -import { sqlClient } from "#/clients/sqlClient.js" -import { Exception } from "#/utilities/exception.js" +import { sqlClient } from "../../clients/sqlClient.js" +import { Exception } from "../../utilities/exception.js" import { SQL, TableConfig } from "drizzle-orm" import { PgTable } from "drizzle-orm/pg-core" diff --git a/packages/api/src/utilities/sql/updateOne.ts b/packages/api/src/utilities/sql/updateOne.ts index 8c2fd8e..9804cc0 100644 --- a/packages/api/src/utilities/sql/updateOne.ts +++ b/packages/api/src/utilities/sql/updateOne.ts @@ -1,5 +1,5 @@ -import { sqlClient } from "#/clients/sqlClient.js" -import { Exception } from "#/utilities/exception.js" +import { sqlClient } from "../../clients/sqlClient.js" +import { Exception } from "../../utilities/exception.js" import { SQL, TableConfig } from "drizzle-orm" import { PgTable, PgUpdateSetSource } from "drizzle-orm/pg-core" diff --git a/packages/api/src/utilities/storage/deleteObject.ts b/packages/api/src/utilities/storage/deleteObject.ts index 667ec6b..1e54cbb 100644 --- a/packages/api/src/utilities/storage/deleteObject.ts +++ b/packages/api/src/utilities/storage/deleteObject.ts @@ -1,6 +1,6 @@ -import { Exception } from "#/utilities/exception.js" -import { getClients } from "#/utilities/getClients.js" -import { getEnv } from "#/utilities/getEnv.js" +import { Exception } from "../../utilities/exception.js" +import { getClients } from "../../utilities/getClients.js" +import { getEnv } from "../../utilities/getEnv.js" import { DeleteObjectCommand } from "@aws-sdk/client-s3" @@ -14,7 +14,7 @@ export async function deleteObject(parameters: { try { const command = new DeleteObjectCommand({ - Bucket: parameters.var.env.STORAGE_NAME, + Bucket: parameters.var.env.STORAGE_BUCKET_NAME, Key: parameters.storageKey }) diff --git a/packages/api/src/utilities/storage/generateDeleteSignedUrl.ts b/packages/api/src/utilities/storage/generateDeleteSignedUrl.ts index 5666260..ff1db14 100644 --- a/packages/api/src/utilities/storage/generateDeleteSignedUrl.ts +++ b/packages/api/src/utilities/storage/generateDeleteSignedUrl.ts @@ -1,6 +1,6 @@ -import { Exception } from "#/utilities/exception.js" -import { getClients } from "#/utilities/getClients.js" -import { getEnv } from "#/utilities/getEnv.js" +import { Exception } from "../../utilities/exception.js" +import { getClients } from "../../utilities/getClients.js" +import { getEnv } from "../../utilities/getEnv.js" import { DeleteObjectCommand } from "@aws-sdk/client-s3" import { getSignedUrl } from "@aws-sdk/s3-request-presigner" @@ -17,7 +17,7 @@ export async function generateDeleteSignedUrl(parameters: { const signedUrl = await getSignedUrl( parameters.var.clients.storage, new DeleteObjectCommand({ - Bucket: parameters.var.env.STORAGE_NAME, + Bucket: parameters.var.env.STORAGE_BUCKET_NAME, Key: parameters.storageKey }), { diff --git a/packages/api/src/utilities/storage/generateGetSignedUrl.ts b/packages/api/src/utilities/storage/generateGetSignedUrl.ts index 296551c..d8f9284 100644 --- a/packages/api/src/utilities/storage/generateGetSignedUrl.ts +++ b/packages/api/src/utilities/storage/generateGetSignedUrl.ts @@ -1,7 +1,7 @@ -import { Exception } from "#/utilities/exception.js" -import { getClients } from "#/utilities/getClients.js" -import { getEnv } from "#/utilities/getEnv.js" -import { storageFileExpiresIn } from "#/utilities/variables.js" +import { Exception } from "../../utilities/exception.js" +import { getClients } from "../../utilities/getClients.js" +import { getEnv } from "../../utilities/getEnv.js" +import { storageFileExpiresIn } from "../../utilities/variables.js" import { GetObjectCommand } from "@aws-sdk/client-s3" import { getSignedUrl } from "@aws-sdk/s3-request-presigner" @@ -18,7 +18,7 @@ export async function generateGetSignedUrl(parameters: { const signedUrl = await getSignedUrl( parameters.var.clients.storage, new GetObjectCommand({ - Bucket: parameters.var.env.STORAGE_NAME, + Bucket: parameters.var.env.STORAGE_BUCKET_NAME, Key: parameters.storageKey }), { diff --git a/packages/api/src/utilities/storage/generatePutSignedUrl.ts b/packages/api/src/utilities/storage/generatePutSignedUrl.ts index a3d6d7c..0d9170a 100644 --- a/packages/api/src/utilities/storage/generatePutSignedUrl.ts +++ b/packages/api/src/utilities/storage/generatePutSignedUrl.ts @@ -1,6 +1,6 @@ -import { Exception } from "#/utilities/exception.js" -import { getClients } from "#/utilities/getClients.js" -import { getEnv } from "#/utilities/getEnv.js" +import { Exception } from "../../utilities/exception.js" +import { getClients } from "../../utilities/getClients.js" +import { getEnv } from "../../utilities/getEnv.js" import { PutObjectCommand } from "@aws-sdk/client-s3" import { getSignedUrl } from "@aws-sdk/s3-request-presigner" @@ -21,7 +21,7 @@ export async function generatePutSignedUrl(parameters: { parameters.var.clients.storage, new PutObjectCommand({ ACL: "private", - Bucket: parameters.var.env.STORAGE_NAME, + Bucket: parameters.var.env.STORAGE_BUCKET_NAME, Key: parameters.storageKey, ContentLength: parameters.contentLength, ContentType: parameters.contentType, diff --git a/packages/api/src/utilities/storage/getObject.ts b/packages/api/src/utilities/storage/getObject.ts index 569eb47..68d087b 100644 --- a/packages/api/src/utilities/storage/getObject.ts +++ b/packages/api/src/utilities/storage/getObject.ts @@ -1,6 +1,6 @@ -import { Exception } from "#/utilities/exception.js" -import { getClients } from "#/utilities/getClients.js" -import { getEnv } from "#/utilities/getEnv.js" +import { Exception } from "../../utilities/exception.js" +import { getClients } from "../../utilities/getClients.js" +import { getEnv } from "../../utilities/getEnv.js" import { GetObjectCommand } from "@aws-sdk/client-s3" @@ -14,7 +14,7 @@ export async function getObject(parameters: { try { const command = new GetObjectCommand({ - Bucket: parameters.var.env.STORAGE_NAME, + Bucket: parameters.var.env.STORAGE_BUCKET_NAME, Key: parameters.storageKey ?? undefined }) diff --git a/packages/api/src/utilities/storage/putObject.ts b/packages/api/src/utilities/storage/putObject.ts index 6bcdb63..b8ce55d 100644 --- a/packages/api/src/utilities/storage/putObject.ts +++ b/packages/api/src/utilities/storage/putObject.ts @@ -1,6 +1,6 @@ -import { Exception } from "#/utilities/exception.js" -import { getClients } from "#/utilities/getClients.js" -import { getEnv } from "#/utilities/getEnv.js" +import { Exception } from "../../utilities/exception.js" +import { getClients } from "../../utilities/getClients.js" +import { getEnv } from "../../utilities/getEnv.js" import { PutObjectCommand } from "@aws-sdk/client-s3" @@ -19,7 +19,7 @@ export async function putObject(parameters: { const command = new PutObjectCommand({ ACL: "private", - Bucket: parameters.var.env.STORAGE_NAME, + Bucket: parameters.var.env.STORAGE_BUCKET_NAME, Key: parameters.storageKey, ContentLength: parameters.contentLength, ContentType: parameters.contentType, diff --git a/packages/api/src/utilities/validate.ts b/packages/api/src/utilities/validate.ts index 9979c02..291f6eb 100644 --- a/packages/api/src/utilities/validate.ts +++ b/packages/api/src/utilities/validate.ts @@ -1,30 +1,30 @@ -import { Exception } from "#/utilities/exception.js" -import * as v from "valibot" - - -export function validate< - T extends v.GenericSchema ->(parameters: { - schema: T - data: v.InferOutput -}) { - - const parsed = v.safeParse( - parameters.schema, - parameters.data, - { - abortEarly: true, - abortPipeEarly: true, - }, - ) - - if (parsed.success === false) { - throw new Exception({ - statusCode: 500, - internalMessage: "Invalid data", - cause: JSON.stringify(v.flatten(parsed.issues)), - }) - } - - return parsed.output +import { Exception } from "../utilities/exception.js" +import * as v from "valibot" + + +export function validate< + T extends v.GenericSchema +>(parameters: { + schema: T + data: v.InferOutput +}) { + + const parsed = v.safeParse( + parameters.schema, + parameters.data, + { + abortEarly: true, + abortPipeEarly: true, + }, + ) + + if (parsed.success === false) { + throw new Exception({ + statusCode: 500, + internalMessage: "Invalid data", + cause: JSON.stringify(v.flatten(parsed.issues)), + }) + } + + return parsed.output } \ No newline at end of file diff --git a/packages/api/src/utilities/variables.ts b/packages/api/src/utilities/variables.ts index 7a0a0f3..75a939f 100644 --- a/packages/api/src/utilities/variables.ts +++ b/packages/api/src/utilities/variables.ts @@ -5,3 +5,18 @@ export const verificationTokenLifetime = 1000 * 60 * 60 * 24 * 1 export const storageFileExpiresIn = 60 * 60 export const cookiePrefix = "arrhes" + +/** + * Returns cookie security options based on the environment. + * - Production: secure + SameSite=None (requires HTTPS, allows cross-site) + * - Development: no secure flag + SameSite=Lax (works over HTTP) + */ +export function getCookieSecurityOptions(env: string): { + secure: boolean + sameSite: "Strict" | "Lax" | "None" +} { + if (env === "production") { + return { secure: true, sameSite: "None" } + } + return { secure: false, sameSite: "Lax" } +} diff --git a/packages/api/src/utilities/workspace/generateDefaultYearData.ts b/packages/api/src/utilities/workspace/generateDefaultYearData.ts index 6a153b0..35ff274 100644 --- a/packages/api/src/utilities/workspace/generateDefaultYearData.ts +++ b/packages/api/src/utilities/workspace/generateDefaultYearData.ts @@ -1,6 +1,6 @@ -// import { defaultAssociationAccounts, defaultAssociationBalanceSheets, defaultAssociationIncomeStatements, DefaultBalanceSheet, defaultCompanyAccounts, defaultCompanyBalanceSheets, defaultCompanyIncomeStatements, DefaultComputation, defaultComputations } from "@arrhes/metadata/components" -// import { returnedSchemas } from "@arrhes/metadata/schemas" -// import { generateId } from "@arrhes/metadata/utilities" +// import { defaultAssociationAccounts, defaultAssociationBalanceSheets, defaultAssociationIncomeStatements, DefaultBalanceSheet, defaultCompanyAccounts, defaultCompanyBalanceSheets, defaultCompanyIncomeStatements, DefaultComputation, defaultComputations } from "@arrhes/application-metadata/components" +// import { returnedSchemas } from "@arrhes/application-metadata/schemas" +// import { generateId } from "@arrhes/application-metadata/utilities" // import * as v from "valibot" diff --git a/packages/api/src/validators/bodyValidator.ts b/packages/api/src/validators/bodyValidator.ts index 7d92ce8..2d8efa9 100644 --- a/packages/api/src/validators/bodyValidator.ts +++ b/packages/api/src/validators/bodyValidator.ts @@ -1,25 +1,25 @@ -import { Exception } from "#/utilities/exception.js" -import { validate } from "#/utilities/validate.js" -import { validator } from "hono/validator" -import * as v from "valibot" - - -export const bodyValidator = >(schema: T) => { - return validator("json", async (value, c) => { - try { - const validatedBody = validate({ - schema: schema, - data: value - }) - return validatedBody - } - catch (error: unknown) { - throw new Exception({ - statusCode: 400, - internalMessage: "The body object can not be parsed", - externalMessage: "Invalid request", - rawError: error - }) - } - }) +import { Exception } from "../utilities/exception.js" +import { validate } from "../utilities/validate.js" +import { validator } from "hono/validator" +import * as v from "valibot" + + +export const bodyValidator = >(schema: T) => { + return validator("json", async (value, c) => { + try { + const validatedBody = validate({ + schema: schema, + data: value + }) + return validatedBody + } + catch (error: unknown) { + throw new Exception({ + statusCode: 400, + internalMessage: "The body object can not be parsed", + externalMessage: "Invalid request", + rawError: error + }) + } + }) } \ No newline at end of file diff --git a/packages/api/tsconfig.json b/packages/api/tsconfig.json index 7f744e1..89970cf 100644 --- a/packages/api/tsconfig.json +++ b/packages/api/tsconfig.json @@ -1,6 +1,20 @@ { - "extends": "../../tsconfig.json", "compilerOptions": { + "jsx": "react-jsx", + "target": "ESNext", + "noImplicitAny": true, + "skipLibCheck": true, + "strict": true, + "strictNullChecks": true, + "forceConsistentCasingInFileNames": true, + "esModuleInterop": true, + "module": "NodeNext", + "moduleResolution": "NodeNext", + "resolveJsonModule": true, + "isolatedModules": true, + "declaration": true, + "declarationMap": true, + "sourceMap": true, "jsxImportSource": "hono/jsx", "rootDir": "./src", "outDir": "./build", diff --git a/packages/platform/eslint.config.js b/packages/dashboard/eslint.config.js similarity index 100% rename from packages/platform/eslint.config.js rename to packages/dashboard/eslint.config.js diff --git a/packages/platform/package.json b/packages/dashboard/package.json similarity index 81% rename from packages/platform/package.json rename to packages/dashboard/package.json index 2a4a251..eb9b491 100644 --- a/packages/platform/package.json +++ b/packages/dashboard/package.json @@ -1,5 +1,5 @@ { - "name": "@arrhes/platform", + "name": "@arrhes/application-dashboard", "type": "module", "private": false, "scripts": { @@ -9,38 +9,34 @@ }, "devDependencies": { "@eslint/js": "9.39.1", - "@tailwindcss/vite": "4.1.17", + "@pandacss/dev": "1.8.1", "@types/node": "24.10.1", "@types/react": "19.2.7", "@types/react-dom": "19.2.3", "@vitejs/plugin-react": "5.1.1", - "clsx": "2.1.1", "eslint": "9.39.1", "eslint-plugin-react-hooks": "7.0.1", "eslint-plugin-react-refresh": "0.4.24", "globals": "16.5.0", - "tailwind-merge": "3.4.0", - "tailwindcss": "4.1.17", "typescript": "5.9.3", "typescript-eslint": "8.48.0", "vite": "7.2.4" }, "dependencies": { - "@arrhes/metadata": "workspace:*", + "@arrhes/application-metadata": "workspace:*", + "@arrhes/ui": "workspace:*", "@hookform/resolvers": "5.2.2", "@radix-ui/react-dialog": "1.1.15", "@radix-ui/react-dropdown-menu": "2.1.16", "@radix-ui/react-popover": "1.1.15", "@radix-ui/react-slot": "1.2.4", "@radix-ui/react-switch": "1.2.6", - "@radix-ui/react-toast": "1.2.15", "@radix-ui/react-tooltip": "1.2.8", "@tabler/icons-react": "3.35.0", "@tanstack/react-query": "5.90.11", "@tanstack/react-router": "1.139.10", "@tanstack/react-table": "8.21.3", "@tanstack/react-virtual": "3.13.12", - "class-variance-authority": "0.7.1", "cmdk": "1.1.1", "react": "19.2.0", "react-dom": "19.2.0", @@ -48,12 +44,6 @@ "react-imask": "7.6.1", "valibot": "1.2.0" }, - "imports": { - "#/*": "./src/*" - }, - "exports": { - "#/*": "./build/*" - }, "browserslist": { "production": [ "cover 99.99%", diff --git a/packages/dashboard/panda.config.ts b/packages/dashboard/panda.config.ts new file mode 100644 index 0000000..d739db2 --- /dev/null +++ b/packages/dashboard/panda.config.ts @@ -0,0 +1,26 @@ +import { defineConfig } from '@pandacss/dev' +import uiConfig from '../ui/panda.config' + + +export default defineConfig({ + // Whether to use css reset + preflight: true, + + // Where to look for your css declarations + include: ['../ui/src/**/*.{ts,tsx}', './src/**/*.{ts,tsx}'], + + // Files to exclude + exclude: [], + + // Use theme from UI package + theme: uiConfig.theme, + + // Import map for the UI package + importMap: '@arrhes/ui', + + // The output directory for your css system + outdir: 'styled-system', + + // Use JSX style props + jsxFramework: "react", +}) diff --git a/packages/dashboard/postcss.config.cjs b/packages/dashboard/postcss.config.cjs new file mode 100644 index 0000000..97a9426 --- /dev/null +++ b/packages/dashboard/postcss.config.cjs @@ -0,0 +1,5 @@ +module.exports = { + plugins: { + "@pandacss/dev/postcss": {}, + }, +} diff --git a/packages/dashboard/public/favicon.svg b/packages/dashboard/public/favicon.svg new file mode 100644 index 0000000..c418b79 --- /dev/null +++ b/packages/dashboard/public/favicon.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/platform/public/robots.txt b/packages/dashboard/public/robots.txt similarity index 100% rename from packages/platform/public/robots.txt rename to packages/dashboard/public/robots.txt diff --git a/packages/platform/public/sitemap.xml b/packages/dashboard/public/sitemap.xml similarity index 100% rename from packages/platform/public/sitemap.xml rename to packages/dashboard/public/sitemap.xml diff --git a/packages/dashboard/src/assets/css/root.css b/packages/dashboard/src/assets/css/root.css new file mode 100644 index 0000000..9c15ae6 --- /dev/null +++ b/packages/dashboard/src/assets/css/root.css @@ -0,0 +1,5 @@ +@layer reset, base, tokens, recipes, utilities; + +/* html { + scrollbar-gutter: stable; +} */ \ No newline at end of file diff --git a/packages/platform/src/assets/images/favicons/apple-touch-icon.png b/packages/dashboard/src/assets/images/favicons/apple-touch-icon.png similarity index 100% rename from packages/platform/src/assets/images/favicons/apple-touch-icon.png rename to packages/dashboard/src/assets/images/favicons/apple-touch-icon.png diff --git a/packages/platform/src/assets/images/favicons/favicon-96x96.png b/packages/dashboard/src/assets/images/favicons/favicon-96x96.png similarity index 100% rename from packages/platform/src/assets/images/favicons/favicon-96x96.png rename to packages/dashboard/src/assets/images/favicons/favicon-96x96.png diff --git a/packages/platform/src/assets/images/favicons/favicon.ico b/packages/dashboard/src/assets/images/favicons/favicon.ico similarity index 100% rename from packages/platform/src/assets/images/favicons/favicon.ico rename to packages/dashboard/src/assets/images/favicons/favicon.ico diff --git a/packages/platform/src/assets/images/favicons/favicon.svg b/packages/dashboard/src/assets/images/favicons/favicon.svg similarity index 100% rename from packages/platform/src/assets/images/favicons/favicon.svg rename to packages/dashboard/src/assets/images/favicons/favicon.svg diff --git a/packages/platform/src/assets/manifest/site.webmanifest b/packages/dashboard/src/assets/manifest/site.webmanifest similarity index 100% rename from packages/platform/src/assets/manifest/site.webmanifest rename to packages/dashboard/src/assets/manifest/site.webmanifest diff --git a/packages/platform/src/assets/manifest/web-app-manifest-192x192.png b/packages/dashboard/src/assets/manifest/web-app-manifest-192x192.png similarity index 100% rename from packages/platform/src/assets/manifest/web-app-manifest-192x192.png rename to packages/dashboard/src/assets/manifest/web-app-manifest-192x192.png diff --git a/packages/platform/src/assets/manifest/web-app-manifest-512x512.png b/packages/dashboard/src/assets/manifest/web-app-manifest-512x512.png similarity index 100% rename from packages/platform/src/assets/manifest/web-app-manifest-512x512.png rename to packages/dashboard/src/assets/manifest/web-app-manifest-512x512.png diff --git a/packages/dashboard/src/components/document/docDefinition.tsx b/packages/dashboard/src/components/document/docDefinition.tsx new file mode 100644 index 0000000..80d8891 --- /dev/null +++ b/packages/dashboard/src/components/document/docDefinition.tsx @@ -0,0 +1,61 @@ +import { css } from "@arrhes/ui/utilities/cn.js" +import { IconBookmark } from "@tabler/icons-react" +import { ReactNode } from "react" + + +export function DocDefinition(props: { + term: string + definition: ReactNode +}) { + return ( +
+
+ + + Définition + +
+
+ {props.term} +
+
+ {props.definition} +
+
+ ) +} diff --git a/packages/dashboard/src/components/document/docExample.tsx b/packages/dashboard/src/components/document/docExample.tsx new file mode 100644 index 0000000..df08715 --- /dev/null +++ b/packages/dashboard/src/components/document/docExample.tsx @@ -0,0 +1,58 @@ +import { css } from "@arrhes/ui/utilities/cn.js" +import { IconInfoCircle } from "@tabler/icons-react" + + +export function DocExample(props: { + title?: string + children: React.ReactNode +}) { + return ( +
+ {props.title && ( +
+ + + {props.title} + +
+ )} +
+ {props.children} +
+
+ ) +} diff --git a/packages/dashboard/src/components/document/docGlossaryEntry.tsx b/packages/dashboard/src/components/document/docGlossaryEntry.tsx new file mode 100644 index 0000000..d4c641c --- /dev/null +++ b/packages/dashboard/src/components/document/docGlossaryEntry.tsx @@ -0,0 +1,33 @@ +import { css } from "@arrhes/ui/utilities/cn.js" +import { ReactNode } from "react" + + +export function DocGlossaryEntry(props: { + term: string + definition: ReactNode +}) { + return ( +
+
+ {props.term} +
+
+ {props.definition} +
+
+ ) +} diff --git a/packages/dashboard/src/components/document/docHeader.tsx b/packages/dashboard/src/components/document/docHeader.tsx new file mode 100644 index 0000000..ab8be93 --- /dev/null +++ b/packages/dashboard/src/components/document/docHeader.tsx @@ -0,0 +1,27 @@ +import { css } from "@arrhes/ui/utilities/cn.js" + + +export function DocHeader(props: { + title: string + description: string +}) { + return ( +
+

+ {props.title} +

+

+ {props.description} +

+
+ ) +} diff --git a/packages/dashboard/src/components/document/docIndexLink.tsx b/packages/dashboard/src/components/document/docIndexLink.tsx new file mode 100644 index 0000000..9594cda --- /dev/null +++ b/packages/dashboard/src/components/document/docIndexLink.tsx @@ -0,0 +1,33 @@ +import { css } from "@arrhes/ui/utilities/cn.js" +import type { ValidRoutes } from "../../routes/platformRouter.js" +import { LinkButton } from "../linkButton.js" + + +export function DocIndexLink(props: { + to: ValidRoutes + label: string +}) { + return ( + + + {props.label} + + ) +} diff --git a/packages/dashboard/src/components/document/docLastUpdate.tsx b/packages/dashboard/src/components/document/docLastUpdate.tsx new file mode 100644 index 0000000..33e8184 --- /dev/null +++ b/packages/dashboard/src/components/document/docLastUpdate.tsx @@ -0,0 +1,18 @@ +import { css } from "@arrhes/ui/utilities/cn.js" + + +export function DocLastUpdate(props: { + date: string +}) { + return ( +
+ Dernière mise à jour : {props.date} +
+ ) +} diff --git a/packages/dashboard/src/components/document/docLink.tsx b/packages/dashboard/src/components/document/docLink.tsx new file mode 100644 index 0000000..7a60652 --- /dev/null +++ b/packages/dashboard/src/components/document/docLink.tsx @@ -0,0 +1,28 @@ +import { css } from "@arrhes/ui/utilities/cn.js" +import type { ValidRoutes } from "../../routes/platformRouter.js" +import { LinkButton } from "../linkButton.js" + + +export function DocLink(props: { + to: ValidRoutes + children: React.ReactNode +}) { + return ( + + {props.children} + + ) +} diff --git a/packages/dashboard/src/components/document/docLinkCard.tsx b/packages/dashboard/src/components/document/docLinkCard.tsx new file mode 100644 index 0000000..990d640 --- /dev/null +++ b/packages/dashboard/src/components/document/docLinkCard.tsx @@ -0,0 +1,75 @@ +import { css } from "@arrhes/ui/utilities/cn.js" +import type { ReactNode } from "react" +import type { ValidRoutes } from "../../routes/platformRouter.js" +import { LinkButton } from "../linkButton.js" + + +export type DocLinkCardColor = "information" | "success" | "primary" | "warning" + +export function DocLinkCard(props: { + icon: ReactNode + iconColor?: DocLinkCardColor + title: string + description: string + to: ValidRoutes +}) { + const colorStyles: Record = { + information: { bg: "information/10", color: "information" }, + success: { bg: "success/10", color: "success" }, + primary: { bg: "primary/10", color: "primary" }, + warning: { bg: "warning/10", color: "warning" }, + } + const style = colorStyles[props.iconColor ?? "primary"] + + return ( + +
+ {props.icon} +
+

+ {props.title} +

+

+ {props.description} +

+
+ ) +} diff --git a/packages/dashboard/src/components/document/docList.tsx b/packages/dashboard/src/components/document/docList.tsx new file mode 100644 index 0000000..df377ef --- /dev/null +++ b/packages/dashboard/src/components/document/docList.tsx @@ -0,0 +1,55 @@ +import { css } from "@arrhes/ui/utilities/cn.js" +import { ReactNode } from "react" + + +export function DocList(props: { + items: ReactNode[] + variant?: "bullet" | "check" +}) { + const variant = props.variant ?? "check" + + return ( +
    + {props.items.map((item, index) => ( +
  • + { + (variant === "check") + ? ( + + ✓ + + ) + : ( + + • + + ) + } + + {item} + +
  • + ))} +
+ ) +} diff --git a/packages/dashboard/src/components/document/docNextPage.tsx b/packages/dashboard/src/components/document/docNextPage.tsx new file mode 100644 index 0000000..36fa108 --- /dev/null +++ b/packages/dashboard/src/components/document/docNextPage.tsx @@ -0,0 +1,39 @@ +import { ButtonContent } from "@arrhes/ui" +import { css } from "@arrhes/ui/utilities/cn.js" +import { IconChevronRight } from "@tabler/icons-react" +import type { ValidRoutes } from "../../routes/platformRouter.js" +import { LinkButton } from "../linkButton.js" + + +export function DocNextPage(props: { + to: ValidRoutes + label: string +}) { + return ( +
+ + Page suivante + + + } + /> + +
+ ) +} diff --git a/packages/dashboard/src/components/document/docParagraph.tsx b/packages/dashboard/src/components/document/docParagraph.tsx new file mode 100644 index 0000000..11c249a --- /dev/null +++ b/packages/dashboard/src/components/document/docParagraph.tsx @@ -0,0 +1,16 @@ +import { css } from "@arrhes/ui/utilities/cn.js" + + +export function DocParagraph(props: { + children: React.ReactNode +}) { + return ( +

+ {props.children} +

+ ) +} diff --git a/packages/dashboard/src/components/document/docRoot.tsx b/packages/dashboard/src/components/document/docRoot.tsx new file mode 100644 index 0000000..16db027 --- /dev/null +++ b/packages/dashboard/src/components/document/docRoot.tsx @@ -0,0 +1,19 @@ +import { css } from "@arrhes/ui/utilities/cn.js" +import { ReactNode } from "react" + + +export function DocRoot(props: { + children: ReactNode +}) { + return ( +
+ {props.children} +
+ ) +} diff --git a/packages/dashboard/src/components/document/docSection.tsx b/packages/dashboard/src/components/document/docSection.tsx new file mode 100644 index 0000000..f6f25a7 --- /dev/null +++ b/packages/dashboard/src/components/document/docSection.tsx @@ -0,0 +1,41 @@ +import { css } from "@arrhes/ui/utilities/cn.js" + + +export function DocSection(props: { + title: string + children: React.ReactNode +}) { + const id = props.title.toLowerCase() + .replace(/[^a-z0-9\s-]/g, '') + .replace(/\s+/g, '-') + + return ( +
+

+ {props.title} +

+
+ {props.children} +
+
+ ) +} diff --git a/packages/dashboard/src/components/document/docSectionCard.tsx b/packages/dashboard/src/components/document/docSectionCard.tsx new file mode 100644 index 0000000..956d28d --- /dev/null +++ b/packages/dashboard/src/components/document/docSectionCard.tsx @@ -0,0 +1,123 @@ +import { ButtonContent } from "@arrhes/ui" +import { css } from "@arrhes/ui/utilities/cn.js" +import { IconChevronRight } from "@tabler/icons-react" +import type { ReactNode } from "react" +import type { ValidRoutes } from "../../routes/platformRouter.js" +import { LinkButton } from "../linkButton.js" + + +export type DocSectionCardColor = "information" | "success" | "primary" | "warning" + +export function DocSectionCard(props: { + icon: ReactNode + iconColor?: DocSectionCardColor + title: string + description: string + links: { to: ValidRoutes; label: string }[] + ctaTo: ValidRoutes + ctaLabel: string +}) { + const colorStyles: Record = { + information: { bg: "information/10", color: "information" }, + success: { bg: "success/10", color: "success" }, + primary: { bg: "primary/10", color: "primary" }, + warning: { bg: "warning/10", color: "warning" }, + } + const style = colorStyles[props.iconColor ?? "primary"] + + return ( +
+ {/* Icon */} +
+ {props.icon} +
+ + {/* Title */} +

+ {props.title} +

+ + {/* Description */} +

+ {props.description} +

+ + {/* Links */} +
+ {props.links.map((link) => ( + + + {link.label} + + ))} +
+ + {/* CTA */} + + } + /> + +
+ ) +} diff --git a/packages/dashboard/src/components/document/docTable.tsx b/packages/dashboard/src/components/document/docTable.tsx new file mode 100644 index 0000000..642bcd6 --- /dev/null +++ b/packages/dashboard/src/components/document/docTable.tsx @@ -0,0 +1,68 @@ +import { css } from "@arrhes/ui/utilities/cn.js" + + +export function DocTable(props: { + headers: string[] + rows: string[][] +}) { + return ( +
+ + + + {props.headers.map((header, index) => ( + + ))} + + + + {props.rows.map((row, rowIndex) => ( + + {row.map((cell, cellIndex) => ( + + ))} + + ))} + +
+ {header} +
+ {cell} +
+
+ ) +} diff --git a/packages/dashboard/src/components/document/docTextSection.tsx b/packages/dashboard/src/components/document/docTextSection.tsx new file mode 100644 index 0000000..bd382d3 --- /dev/null +++ b/packages/dashboard/src/components/document/docTextSection.tsx @@ -0,0 +1,54 @@ +import { css } from "@arrhes/ui/utilities/cn.js" + + +export function DocTextSection(props: { + title: string + children: React.ReactNode +}) { + return ( +
+

+ {props.title} +

+
+ {props.children} +
+
+ ) +} diff --git a/packages/dashboard/src/components/document/docTip.tsx b/packages/dashboard/src/components/document/docTip.tsx new file mode 100644 index 0000000..a7d5443 --- /dev/null +++ b/packages/dashboard/src/components/document/docTip.tsx @@ -0,0 +1,118 @@ +import { css } from "@arrhes/ui/utilities/cn.js" +import { + IconAlertTriangle, + IconBulb, + IconCircleCheck, + IconInfoCircle +} from "@tabler/icons-react" + + + +const variantConfig: Record<"tip" | "warning" | "info" | "success", { + icon: React.ReactNode + label: string + backgroundColor: string + borderColor: string + accentColor: string + iconColor: string + labelColor: string +}> = { + tip: { + icon: , + label: "Conseil", + backgroundColor: "warning/5", + borderColor: "warning/10", + accentColor: "warning", + iconColor: "warning", + labelColor: "warning" + }, + warning: { + icon: , + label: "Attention", + backgroundColor: "error/5", + borderColor: "error/10", + accentColor: "error", + iconColor: "error", + labelColor: "error" + }, + info: { + icon: , + label: "Information", + backgroundColor: "information/5", + borderColor: "information/10", + accentColor: "information", + iconColor: "information", + labelColor: "information" + }, + success: { + icon: , + label: "Félicitations", + backgroundColor: "success/5", + borderColor: "success/10", + accentColor: "success", + iconColor: "success", + labelColor: "success" + } +} + + +export function DocTip(props: { + variant?: keyof typeof variantConfig + label?: string + children: React.ReactNode +}) { + const variant = props.variant ?? "tip" + const config = variantConfig[variant] + const label = props.label ?? config.label + + return ( +
+
+
+ {config.icon} +
+ + {label} + +
+ + {props.children} + +
+ ) +} diff --git a/packages/dashboard/src/components/formats/formatBase.tsx b/packages/dashboard/src/components/formats/formatBase.tsx new file mode 100644 index 0000000..3383098 --- /dev/null +++ b/packages/dashboard/src/components/formats/formatBase.tsx @@ -0,0 +1,28 @@ +import { css, cx } from "@arrhes/ui/utilities/cn.js" +import { ComponentProps, ReactNode } from "react" + + +type FormatBase = { + children: ReactNode + className?: ComponentProps<'div'>['className'] +} + +export function FormatBase(props: FormatBase) { + return ( +
+ {props.children} +
+ ) +} diff --git a/packages/platform/src/components/formats/formatBoolean.tsx b/packages/dashboard/src/components/formats/formatBoolean.tsx similarity index 88% rename from packages/platform/src/components/formats/formatBoolean.tsx rename to packages/dashboard/src/components/formats/formatBoolean.tsx index 06685ed..4489f8b 100644 --- a/packages/platform/src/components/formats/formatBoolean.tsx +++ b/packages/dashboard/src/components/formats/formatBoolean.tsx @@ -1,25 +1,25 @@ -import { Chip } from "#/components/layouts/chip.js" -import { ComponentProps } from "react" -import { FormatBase } from "./formatBase.js" - - -export function formatBoolean(boolean?: boolean | null) { - if (!boolean) return "Non" - return "Oui" -} - - -export function FormatBoolean(props: { - boolean?: boolean | null - text?: string - className?: ComponentProps<'div'>['className'] -}) { - return ( - - - - ) -} +import { Chip } from "../../components/layouts/chip.js" +import { ComponentProps } from "react" +import { FormatBase } from "./formatBase.js" + + +export function formatBoolean(boolean?: boolean | null) { + if (!boolean) return "Non" + return "Oui" +} + + +export function FormatBoolean(props: { + boolean?: boolean | null + text?: string + className?: ComponentProps<'div'>['className'] +}) { + return ( + + + + ) +} diff --git a/packages/platform/src/components/formats/formatDate.tsx b/packages/dashboard/src/components/formats/formatDate.tsx similarity index 91% rename from packages/platform/src/components/formats/formatDate.tsx rename to packages/dashboard/src/components/formats/formatDate.tsx index 3bec55e..05a4fb7 100644 --- a/packages/platform/src/components/formats/formatDate.tsx +++ b/packages/dashboard/src/components/formats/formatDate.tsx @@ -1,38 +1,38 @@ -import { FormatText } from "#/components/formats/formatText.js" -import { ComponentProps } from "react" -import { FormatNull } from "./formatNull.js" - - -export function formatDate(rawDate?: string | Date | undefined | null) { - if ((!rawDate) || (String(new Date(rawDate)) === "Invalid Date")) return undefined - - const date = new Date(rawDate) - let day = String(date.getDate()) - let month = String(date.getMonth() + 1) - let year = String(date.getFullYear()) - let hour = String(date.getHours()) - let minute = String(date.getMinutes()) - - if (date.getDate() < 10) day = "0" + day - if ((date.getMonth() + 1) < 10) month = "0" + month - if ((date.getHours()) < 10) hour = "0" + hour - if ((date.getMinutes()) < 10) minute = "0" + minute - - return `${[day, month, year].join('/')}` -} - - -export function FormatDate(props: { - date?: string | Date | undefined | null - className?: ComponentProps<'div'>['className'] -}) { - if (!props.date) return - if (String(new Date(props.date)) === "Invalid Date") return - return ( - - {formatDate(props.date)} - - ) -} +import { FormatText } from "../../components/formats/formatText.js" +import { ComponentProps } from "react" +import { FormatNull } from "./formatNull.js" + + +export function formatDate(rawDate?: string | Date | undefined | null) { + if ((!rawDate) || (String(new Date(rawDate)) === "Invalid Date")) return undefined + + const date = new Date(rawDate) + let day = String(date.getDate()) + let month = String(date.getMonth() + 1) + let year = String(date.getFullYear()) + let hour = String(date.getHours()) + let minute = String(date.getMinutes()) + + if (date.getDate() < 10) day = "0" + day + if ((date.getMonth() + 1) < 10) month = "0" + month + if ((date.getHours()) < 10) hour = "0" + hour + if ((date.getMinutes()) < 10) minute = "0" + minute + + return `${[day, month, year].join('/')}` +} + + +export function FormatDate(props: { + date?: string | Date | undefined | null + className?: ComponentProps<'div'>['className'] +}) { + if (!props.date) return + if (String(new Date(props.date)) === "Invalid Date") return + return ( + + {formatDate(props.date)} + + ) +} diff --git a/packages/platform/src/components/formats/formatDateTime.tsx b/packages/dashboard/src/components/formats/formatDateTime.tsx similarity index 75% rename from packages/platform/src/components/formats/formatDateTime.tsx rename to packages/dashboard/src/components/formats/formatDateTime.tsx index 44e1c18..08ec6aa 100644 --- a/packages/platform/src/components/formats/formatDateTime.tsx +++ b/packages/dashboard/src/components/formats/formatDateTime.tsx @@ -1,51 +1,61 @@ -import { ComponentProps } from "react" -import { FormatNull } from "./formatNull.js" - - -export function formatDateTime(rawDate?: string | Date | undefined | null) { - if ((!rawDate) || (String(new Date(rawDate)) === "Invalid Date")) return "/" - - const date = new Date(rawDate) - let day = String(date.getDate()) - let month = String(date.getMonth() + 1) - let year = String(date.getFullYear()) - let hour = String(date.getHours()) - let minute = String(date.getMinutes()) - - if (date.getDate() < 10) day = "0" + day - if ((date.getMonth() + 1) < 10) month = "0" + month - if ((date.getHours()) < 10) hour = "0" + hour - if ((date.getMinutes()) < 10) minute = "0" + minute - - return `${[day, month, year].join('/')} ${[hour, minute].join(':')}` -} - - -type FormatDateTime = { - date?: string | Date | undefined | null - className?: ComponentProps<'div'>['className'] -} - -export function FormatDateTime(props: FormatDateTime) { - if (!props.date) return - if (String(new Date(props.date)) === "Invalid Date") return - - const date = new Date(props.date) - let day = String(date.getDate()) - let month = String(date.getMonth() + 1) - let year = String(date.getFullYear()) - let hour = String(date.getHours()) - let minute = String(date.getMinutes()) - - if (date.getDate() < 10) day = "0" + day - if ((date.getMonth() + 1) < 10) month = "0" + month - if ((date.getHours()) < 10) hour = "0" + hour - if ((date.getMinutes()) < 10) minute = "0" + minute - - return ( -
- {`${[day, month, year].join('/')}`} - {`${[hour, minute].join(':')}`} -
- ) -} +import { css } from "@arrhes/ui/utilities/cn.js" +import { ComponentProps } from "react" +import { FormatNull } from "./formatNull.js" + + +export function formatDateTime(rawDate?: string | Date | undefined | null) { + if ((!rawDate) || (String(new Date(rawDate)) === "Invalid Date")) return "/" + + const date = new Date(rawDate) + let day = String(date.getDate()) + let month = String(date.getMonth() + 1) + let year = String(date.getFullYear()) + let hour = String(date.getHours()) + let minute = String(date.getMinutes()) + + if (date.getDate() < 10) day = "0" + day + if ((date.getMonth() + 1) < 10) month = "0" + month + if ((date.getHours()) < 10) hour = "0" + hour + if ((date.getMinutes()) < 10) minute = "0" + minute + + return `${[day, month, year].join('/')} ${[hour, minute].join(':')}` +} + + +type FormatDateTime = { + date?: string | Date | undefined | null + className?: ComponentProps<'div'>['className'] +} + +export function FormatDateTime(props: FormatDateTime) { + if (!props.date) return + if (String(new Date(props.date)) === "Invalid Date") return + + const date = new Date(props.date) + let day = String(date.getDate()) + let month = String(date.getMonth() + 1) + let year = String(date.getFullYear()) + let hour = String(date.getHours()) + let minute = String(date.getMinutes()) + + if (date.getDate() < 10) day = "0" + day + if ((date.getMonth() + 1) < 10) month = "0" + month + if ((date.getHours()) < 10) hour = "0" + hour + if ((date.getMinutes()) < 10) minute = "0" + minute + + return ( +
+ {`${[day, month, year].join('/')}`} + {`${[hour, minute].join(':')}`} +
+ ) +} diff --git a/packages/dashboard/src/components/formats/formatError.tsx b/packages/dashboard/src/components/formats/formatError.tsx new file mode 100644 index 0000000..2b0ddea --- /dev/null +++ b/packages/dashboard/src/components/formats/formatError.tsx @@ -0,0 +1,29 @@ +import { css } from "@arrhes/ui/utilities/cn.js" +import { ComponentProps } from "react" +import { FormatBase } from "./formatBase.js" + + + +export function FormatError(props: { + text: string + className?: ComponentProps<'div'>['className'] +}) { + return ( + + + {props.text} + + + ) +} diff --git a/packages/platform/src/components/formats/formatFileSize.tsx b/packages/dashboard/src/components/formats/formatFileSize.tsx similarity index 61% rename from packages/platform/src/components/formats/formatFileSize.tsx rename to packages/dashboard/src/components/formats/formatFileSize.tsx index fb91a47..4a6bf4e 100644 --- a/packages/platform/src/components/formats/formatFileSize.tsx +++ b/packages/dashboard/src/components/formats/formatFileSize.tsx @@ -1,32 +1,41 @@ -import { FormatBase } from "#/components/formats/formatBase.js" -import { FormatNull } from "#/components/formats/formatNull.js" -import { ComponentProps } from "react" - - -const sizes = ['o', 'ko', 'Mo', 'Go', 'To'] - -export function formatFileSize(size?: number | null) { - if (size === undefined || size === null) return "/" - - if (size == 0) return `0 ${sizes.at(0)}` - const i = Math.floor(Math.log(size) / Math.log(1000)) - return `${parseFloat((size / Math.pow(1000, i)).toFixed(2))} ${sizes.at(i)}` - -} - - -type FormatFileSize = { - size?: number | null - className?: ComponentProps<'div'>['className'] -} - -export function FormatFileSize(props: FormatFileSize) { - if (props.size === undefined || props.size === null) return - return ( - - - {formatFileSize(props.size)} - - - ) -} +import { css } from "@arrhes/ui/utilities/cn.js" +import { ComponentProps } from "react" +import { FormatBase } from "../../components/formats/formatBase.js" +import { FormatNull } from "../../components/formats/formatNull.js" + + +const sizes = ['o', 'ko', 'Mo', 'Go', 'To'] + +export function formatFileSize(size?: number | null) { + if (size === undefined || size === null) return "/" + + if (size == 0) return `0 ${sizes.at(0)}` + const i = Math.floor(Math.log(size) / Math.log(1000)) + return `${parseFloat((size / Math.pow(1000, i)).toFixed(2))} ${sizes.at(i)}` + +} + + +type FormatFileSize = { + size?: number | null + className?: ComponentProps<'div'>['className'] +} + +export function FormatFileSize(props: FormatFileSize) { + if (props.size === undefined || props.size === null) return + return ( + + + {formatFileSize(props.size)} + + + ) +} diff --git a/packages/platform/src/components/formats/formatLink.tsx b/packages/dashboard/src/components/formats/formatLink.tsx similarity index 52% rename from packages/platform/src/components/formats/formatLink.tsx rename to packages/dashboard/src/components/formats/formatLink.tsx index 602f35d..51eb76a 100644 --- a/packages/platform/src/components/formats/formatLink.tsx +++ b/packages/dashboard/src/components/formats/formatLink.tsx @@ -1,33 +1,47 @@ -import { Button } from "#/components/buttons/button.js" -import { toast } from "#/contexts/toasts/useToast.js" -import { ComponentProps } from "react" -import { FormatBase } from "./formatBase.js" -import { FormatNull } from "./formatNull.js" - - -type FormatLinkProps = { - text: string | null - className?: ComponentProps<'span'>['className'] -} - -export function FormatLink(props: FormatLinkProps) { - if (!props.text) return - - const copyContent = (toCopy: string | null) => { - toast({ title: "Contenu copié dans le presse-papier.", variant: "information" }) - return navigator.clipboard.writeText(!toCopy ? "" : toCopy) - } - - return ( - - - - ) -} +import { Button } from "@arrhes/ui" +import { css } from "@arrhes/ui/utilities/cn.js" +import { ComponentProps } from "react" +import { toast } from "../../contexts/toasts/useToast.js" +import { FormatBase } from "./formatBase.js" +import { FormatNull } from "./formatNull.js" + + +type FormatLinkProps = { + text: string | null + className?: ComponentProps<'span'>['className'] +} + +export function FormatLink(props: FormatLinkProps) { + if (!props.text) return + + const copyContent = (toCopy: string | null) => { + toast({ title: "Contenu copié dans le presse-papier.", variant: "information" }) + return navigator.clipboard.writeText(!toCopy ? "" : toCopy) + } + + return ( + + + + ) +} diff --git a/packages/dashboard/src/components/formats/formatNull.tsx b/packages/dashboard/src/components/formats/formatNull.tsx new file mode 100644 index 0000000..79ce97c --- /dev/null +++ b/packages/dashboard/src/components/formats/formatNull.tsx @@ -0,0 +1,28 @@ +import { css, cx } from "@arrhes/ui/utilities/cn.js" +import { ComponentProps } from "react" + + +export function FormatNull(props: { + text?: string + className?: ComponentProps<'span'>['className'] +}) { + return ( + + {props.text ?? "/"} + + ) +} diff --git a/packages/platform/src/components/formats/formatPrice.tsx b/packages/dashboard/src/components/formats/formatPrice.tsx similarity index 78% rename from packages/platform/src/components/formats/formatPrice.tsx rename to packages/dashboard/src/components/formats/formatPrice.tsx index 7b2b697..c5b24d4 100644 --- a/packages/platform/src/components/formats/formatPrice.tsx +++ b/packages/dashboard/src/components/formats/formatPrice.tsx @@ -1,53 +1,57 @@ -import { FormatNull } from "#/components/formats/formatNull.js" -import { cn } from "#/utilities/cn.js" -import { ComponentProps } from "react" - - -export function formatPrice(parameters: { - price?: number | null | string -}) { - if (parameters.price === undefined || parameters.price === null) return "/" - const price = Number(parameters.price) - const processedPrice = Math.abs(price) < 0.0090 - ? 0 - : price - return ( - new Intl.NumberFormat("fr", { - minimumFractionDigits: 2, - maximumFractionDigits: 2, - //@ts-ignore - roundingMode: "halfExpand" - }).format(processedPrice).replace(/,/g, '.') - ) -} - - -export function FormatPrice(props: { - price?: number | null | string - className?: ComponentProps<'div'>['className'] -}) { - if (props.price === undefined || props.price === null) { - return ( - - ) - } - const price = Number(props.price) - const processedPrice = Math.abs(price) < 0.0090 - ? 0 - : price - return ( - - {processedPrice < 0 - ? `(${formatPrice({ - price: Math.abs(processedPrice) - })})` - : formatPrice({ - price: Math.abs(processedPrice) - })} - - ) -} +import { css, cx } from "@arrhes/ui/utilities/cn.js" +import { ComponentProps } from "react" +import { FormatNull } from "../../components/formats/formatNull.js" + + +export function formatPrice(parameters: { + price?: number | null | string +}) { + if (parameters.price === undefined || parameters.price === null) return "/" + const price = Number(parameters.price) + const processedPrice = Math.abs(price) < 0.0090 + ? 0 + : price + return ( + new Intl.NumberFormat("fr", { + minimumFractionDigits: 2, + maximumFractionDigits: 2, + //@ts-ignore + roundingMode: "halfExpand" + }).format(processedPrice).replace(/,/g, '.') + ) +} + + +export function FormatPrice(props: { + price?: number | null | string + className?: ComponentProps<'div'>['className'] +}) { + if (props.price === undefined || props.price === null) { + return ( + + ) + } + const price = Number(props.price) + const processedPrice = Math.abs(price) < 0.0090 + ? 0 + : price + return ( + + {processedPrice < 0 + ? `(${formatPrice({ + price: Math.abs(processedPrice) + })})` + : formatPrice({ + price: Math.abs(processedPrice) + })} + + ) +} diff --git a/packages/platform/src/components/formats/formatSelect.tsx b/packages/dashboard/src/components/formats/formatSelect.tsx similarity index 89% rename from packages/platform/src/components/formats/formatSelect.tsx rename to packages/dashboard/src/components/formats/formatSelect.tsx index d83ac62..1d6df2b 100644 --- a/packages/platform/src/components/formats/formatSelect.tsx +++ b/packages/dashboard/src/components/formats/formatSelect.tsx @@ -1,30 +1,30 @@ -import { Chip, ChipColors } from "#/components/layouts/chip.js" -import { ComponentProps } from "react" -import { FormatBase } from "./formatBase.js" -import { FormatNull } from "./formatNull.js" - - -export function formatSelect(key: string | null | undefined, options: { key: string, label: string }[]) { - return options.find(x => x.key === key)?.label ?? "" -} - - -type FormatSelect = { - option?: string | null - options: Array<{ - key: string - label: string - }> - color?: ChipColors - className?: ComponentProps<'div'>['className'] -} - -export function FormatSelect(props: FormatSelect) { - const option = formatSelect(props.option, props.options) - if (!option) return - return ( - - - - ) -} +import { Chip, ChipColors } from "../../components/layouts/chip.js" +import { ComponentProps } from "react" +import { FormatBase } from "./formatBase.js" +import { FormatNull } from "./formatNull.js" + + +export function formatSelect(key: string | null | undefined, options: { key: string, label: string }[]) { + return options.find(x => x.key === key)?.label ?? "" +} + + +type FormatSelect = { + option?: string | null + options: Array<{ + key: string + label: string + }> + color?: ChipColors + className?: ComponentProps<'div'>['className'] +} + +export function FormatSelect(props: FormatSelect) { + const option = formatSelect(props.option, props.options) + if (!option) return + return ( + + + + ) +} diff --git a/packages/platform/src/components/formats/formatText.tsx b/packages/dashboard/src/components/formats/formatText.tsx similarity index 53% rename from packages/platform/src/components/formats/formatText.tsx rename to packages/dashboard/src/components/formats/formatText.tsx index c34a0f4..ea667d9 100644 --- a/packages/platform/src/components/formats/formatText.tsx +++ b/packages/dashboard/src/components/formats/formatText.tsx @@ -1,22 +1,27 @@ -import { cn } from "#/utilities/cn.js" -import { ComponentProps, ReactNode } from "react" -import { FormatNull } from "./formatNull.js" - - -export function FormatText(props: { - wrap?: boolean - className?: ComponentProps<'span'>['className'] - children?: ReactNode -} -) { - if (!props.children) return - return ( - - {props.children} - - ) -} +import { css, cx } from "@arrhes/ui/utilities/cn.js" +import { ComponentProps, ReactNode } from "react" +import { FormatNull } from "./formatNull.js" + + +export function FormatText(props: { + wrap?: boolean + className?: ComponentProps<'span'>['className'] + children?: ReactNode +} +) { + if (!props.children) return + return ( + + {props.children} + + ) +} diff --git a/packages/platform/src/components/forms/formControl.tsx b/packages/dashboard/src/components/forms/formControl.tsx similarity index 88% rename from packages/platform/src/components/forms/formControl.tsx rename to packages/dashboard/src/components/forms/formControl.tsx index f41f457..7e164e1 100644 --- a/packages/platform/src/components/forms/formControl.tsx +++ b/packages/dashboard/src/components/forms/formControl.tsx @@ -1,28 +1,28 @@ -import { CircularLoader } from "#/components/layouts/circularLoader.js" -import { Slot } from "@radix-ui/react-slot" -import { ComponentProps, Suspense } from "react" -import { useFormField } from "./useFormField.js" - - -type FormControl = ComponentProps - -export function FormControl(props: FormControl) { - const { error, formItemId, formDescriptionId, formMessageId } = useFormField() - - return ( - } - > - - - ) +import { CircularLoader } from "../../components/layouts/circularLoader.js" +import { Slot } from "@radix-ui/react-slot" +import { ComponentProps, Suspense } from "react" +import { useFormField } from "./useFormField.js" + + +type FormControl = ComponentProps + +export function FormControl(props: FormControl) { + const { error, formItemId, formDescriptionId, formMessageId } = useFormField() + + return ( + } + > + + + ) } \ No newline at end of file diff --git a/packages/platform/src/components/forms/formError.tsx b/packages/dashboard/src/components/forms/formError.tsx similarity index 65% rename from packages/platform/src/components/forms/formError.tsx rename to packages/dashboard/src/components/forms/formError.tsx index cce02b5..c7d3147 100644 --- a/packages/platform/src/components/forms/formError.tsx +++ b/packages/dashboard/src/components/forms/formError.tsx @@ -1,24 +1,31 @@ -import { cn } from "#/utilities/cn.js" -import { forwardRef } from "react" -import { useFormField } from "./useFormField.js" - - -export const FormError = forwardRef< - HTMLParagraphElement, - React.HTMLAttributes ->(function (props, ref) { - const { error, formMessageId } = useFormField() - const body = error ? String(error?.message) : props.children - - if (!body) return null - return ( -

- {body} -

- ) -}) +import { css, cx } from "@arrhes/ui/utilities/cn.js" +import { forwardRef } from "react" +import { useFormField } from "./useFormField.js" + + +export const FormError = forwardRef< + HTMLParagraphElement, + React.HTMLAttributes +>(function (props, ref) { + const { error, formMessageId } = useFormField() + const body = error ? String(error?.message) : props.children + + if (!body) return null + return ( +

+ {body} +

+ ) +}) diff --git a/packages/platform/src/components/forms/formField.tsx b/packages/dashboard/src/components/forms/formField.tsx similarity index 100% rename from packages/platform/src/components/forms/formField.tsx rename to packages/dashboard/src/components/forms/formField.tsx diff --git a/packages/platform/src/components/forms/formFieldContext.tsx b/packages/dashboard/src/components/forms/formFieldContext.tsx similarity index 100% rename from packages/platform/src/components/forms/formFieldContext.tsx rename to packages/dashboard/src/components/forms/formFieldContext.tsx diff --git a/packages/dashboard/src/components/forms/formItem.tsx b/packages/dashboard/src/components/forms/formItem.tsx new file mode 100644 index 0000000..bca5b2d --- /dev/null +++ b/packages/dashboard/src/components/forms/formItem.tsx @@ -0,0 +1,29 @@ +import { css, cx } from "@arrhes/ui/utilities/cn.js" +import { HTMLAttributes, useId } from "react" +import { FormItemContext } from "./formItemContext.js" + + +type FormItem = HTMLAttributes + +export function FormItem(props: FormItem) { + const id = useId() + + return ( + +
+ + ) +} \ No newline at end of file diff --git a/packages/platform/src/components/forms/formItemContext.tsx b/packages/dashboard/src/components/forms/formItemContext.tsx similarity index 100% rename from packages/platform/src/components/forms/formItemContext.tsx rename to packages/dashboard/src/components/forms/formItemContext.tsx diff --git a/packages/dashboard/src/components/forms/formLabel.tsx b/packages/dashboard/src/components/forms/formLabel.tsx new file mode 100644 index 0000000..fe70f99 --- /dev/null +++ b/packages/dashboard/src/components/forms/formLabel.tsx @@ -0,0 +1,98 @@ + +import { css } from "@arrhes/ui/utilities/cn.js" +import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@radix-ui/react-tooltip" +import { IconInfoSquare } from "@tabler/icons-react" +import { HTMLAttributes } from "react" +import { useFormField } from "./useFormField.js" + + +type FormLabel = { + label: string | undefined + isRequired?: boolean + description?: string | undefined + tooltip?: string | undefined + labelProps?: HTMLAttributes +} + +export function FormLabel(props: FormLabel) { + const { formItemId } = useFormField() + + return ( + + ) +} \ No newline at end of file diff --git a/packages/platform/src/components/forms/formRoot.tsx b/packages/dashboard/src/components/forms/formRoot.tsx similarity index 55% rename from packages/platform/src/components/forms/formRoot.tsx rename to packages/dashboard/src/components/forms/formRoot.tsx index b32f070..a3077c6 100644 --- a/packages/platform/src/components/forms/formRoot.tsx +++ b/packages/dashboard/src/components/forms/formRoot.tsx @@ -1,87 +1,122 @@ -import { ButtonPlain } from "#/components/buttons/buttonPlain.js" -import { cn } from "#/utilities/cn.js" -import { valibotResolver } from "@hookform/resolvers/valibot" -import { ReactElement, useEffect, useRef } from "react" -import { DefaultValues, FormProvider, useForm, UseFormReturn } from "react-hook-form" -import * as v from "valibot" - - -export function FormRoot< - T extends Record, - U extends v.GenericSchema ->(props: { - schema: U - defaultValues: DefaultValues> - onSubmit: (data: v.InferOutput) => Promise - onCancel: ((data: v.InferOutput) => void) | (() => Promise) | undefined - onSuccess: ((data: v.InferOutput) => void) | (() => Promise) | undefined - resetOnSubmit?: boolean - submitOnPressEnterKey?: boolean - submitButtonProps: Parameters[0] - children: (form: UseFormReturn, any, v.InferOutput>) => ReactElement -}) { - const form = useForm({ - mode: "onSubmit", - criteriaMode: "all", - shouldFocusError: true, - defaultValues: props.defaultValues, - resolver: valibotResolver(props.schema), - }) - const submitButtonRef = useRef(null) - - useEffect(() => { - const listener = async (event: KeyboardEvent) => { - if (event.code === "Enter" || event.code === "NumpadEnter") { - event.preventDefault() - submitButtonRef.current?.click() - } - } - document.addEventListener("keydown", listener) - return () => { - document.removeEventListener("keydown", listener) - } - }, []) - - return ( - -
-
-
- {props.children(form)} -
- { - event.preventDefault() - - const triggerResponse = await form.trigger() - if (!triggerResponse) return - - const data = form.getValues() - const response = await props.onSubmit(data) - if (!response) return - - if (props.resetOnSubmit === true) { - form.reset() - } - - if (props.onSuccess !== undefined) { - await props.onSuccess(data) - } - }} - /> -
-
-
- ) -} +import type { ButtonColor, ButtonVariant } from "@arrhes/ui" +import { Button, ButtonContent } from "@arrhes/ui" +import { css } from "@arrhes/ui/utilities/cn.js" +import { valibotResolver } from "@hookform/resolvers/valibot" +import type { Icon, IconProps } from "@tabler/icons-react" +import { ReactElement, useEffect, useRef } from "react" +import { DefaultValues, FormProvider, useForm, UseFormReturn } from "react-hook-form" +import * as v from "valibot" + + +export function FormRoot< + T extends Record, + U extends v.GenericSchema +>(props: { + schema: U + defaultValues: DefaultValues> + onSubmit: (data: v.InferOutput) => Promise + onCancel: ((data: v.InferOutput) => void) | (() => Promise) | undefined + onSuccess: ((data: v.InferOutput) => void) | (() => Promise) | undefined + resetOnSubmit?: boolean + submitOnPressEnterKey?: boolean + submitButtonProps: { + text?: string + title?: string + color?: ButtonColor + variant?: ButtonVariant + className?: string + leftIcon?: ReactElement> + rightIcon?: ReactElement> + } + children: (form: UseFormReturn, any, v.InferOutput>) => ReactElement +}) { + const form = useForm({ + mode: "onSubmit", + criteriaMode: "all", + shouldFocusError: true, + defaultValues: props.defaultValues, + resolver: valibotResolver(props.schema), + }) + const submitButtonRef = useRef(null) + + useEffect(() => { + const listener = async (event: KeyboardEvent) => { + if (event.code === "Enter" || event.code === "NumpadEnter") { + event.preventDefault() + submitButtonRef.current?.click() + } + } + document.addEventListener("keydown", listener) + return () => { + document.removeEventListener("keydown", listener) + } + }, []) + + return ( + +
+
+
+ {props.children(form)} +
+ +
+
+
+ ) +} diff --git a/packages/dashboard/src/components/forms/formSubmit.tsx b/packages/dashboard/src/components/forms/formSubmit.tsx new file mode 100644 index 0000000..53c1a2f --- /dev/null +++ b/packages/dashboard/src/components/forms/formSubmit.tsx @@ -0,0 +1,53 @@ +import { Button, ButtonContent } from "@arrhes/ui" +import { css } from "@arrhes/ui/utilities/cn.js" + + +export type FormSubmit = { + previousLabel?: string + previousCallback?: (data?: T) => Promise + nextLabel: string + nextCallback: (data?: T) => Promise + stepCount?: string + stepName?: string +} + + +export function FormSubmit(props: FormSubmit) { + const handleNext = async () => { + await props.nextCallback() + } + + const handlePrevious = () => { + if (props.previousCallback === undefined) return undefined + props.previousCallback() + } + + return ( +
+
+ { + (props.previousCallback === undefined) ? null : ( + + ) + } + +
+ {(!props.stepCount && !props.stepName) ? null : +
+ {(!props.stepCount) ? null : {props.stepCount}} + {(!props.stepName) ? null : {props.stepName}} +
+ } +
+ ) +} diff --git a/packages/platform/src/components/forms/useFormField.tsx b/packages/dashboard/src/components/forms/useFormField.tsx similarity index 91% rename from packages/platform/src/components/forms/useFormField.tsx rename to packages/dashboard/src/components/forms/useFormField.tsx index 16113d2..e5c6e1e 100644 --- a/packages/platform/src/components/forms/useFormField.tsx +++ b/packages/dashboard/src/components/forms/useFormField.tsx @@ -1,31 +1,31 @@ -import { ClientError } from "#/utilities/clientError.js" -import { useContext } from "react" -import { useFormContext } from "react-hook-form" -import { FormFieldContext } from "./formFieldContext.js" -import { FormItemContext } from "./formItemContext.js" - - -export const useFormField = () => { - const fieldContext = useContext(FormFieldContext) - const itemContext = useContext(FormItemContext) - const { getFieldState, formState } = useFormContext() - - const fieldState = getFieldState(fieldContext.name, formState) - - if (!fieldContext) { - throw new ClientError({ - message: "useFormField should be used within ", - }) - } - - const { id } = itemContext - - return { - id, - name: fieldContext.name, - formItemId: `${id}-form-item`, - formDescriptionId: `${id}-form-item-description`, - formMessageId: `${id}-form-item-message`, - ...fieldState, - } +import { ClientError } from "../../utilities/clientError.js" +import { useContext } from "react" +import { useFormContext } from "react-hook-form" +import { FormFieldContext } from "./formFieldContext.js" +import { FormItemContext } from "./formItemContext.js" + + +export const useFormField = () => { + const fieldContext = useContext(FormFieldContext) + const itemContext = useContext(FormItemContext) + const { getFieldState, formState } = useFormContext() + + const fieldState = getFieldState(fieldContext.name, formState) + + if (!fieldContext) { + throw new ClientError({ + message: "useFormField should be used within ", + }) + } + + const { id } = itemContext + + return { + id, + name: fieldContext.name, + formItemId: `${id}-form-item`, + formDescriptionId: `${id}-form-item-description`, + formMessageId: `${id}-form-item-message`, + ...fieldState, + } } \ No newline at end of file diff --git a/packages/platform/src/components/inputs/inputCombobox.tsx b/packages/dashboard/src/components/inputs/inputCombobox.tsx similarity index 58% rename from packages/platform/src/components/inputs/inputCombobox.tsx rename to packages/dashboard/src/components/inputs/inputCombobox.tsx index fbe8003..8617e05 100644 --- a/packages/platform/src/components/inputs/inputCombobox.tsx +++ b/packages/dashboard/src/components/inputs/inputCombobox.tsx @@ -1,169 +1,199 @@ - -import { Button } from "#/components/buttons/button.js" -import { FormatNull } from "#/components/formats/formatNull.js" -import { CircularLoader } from "#/components/layouts/circularLoader.js" -import { Virtualizer } from "#/components/layouts/virtualizer.js" -import { Popover } from "#/components/overlays/popover/popover.js" -import { cn } from "#/utilities/cn.js" -import { debounce } from "#/utilities/debounce.js" -import { IconCheck, IconChevronDown } from "@tabler/icons-react" -import { ComponentProps, useEffect, useState } from "react" -import { FieldError } from "react-hook-form" - - -export function InputCombobox(props: { - error?: FieldError - placeholder?: string - value?: TValue | null - defaultValue?: TValue | null - onChange: (value?: TValue | null) => void - options: Array<{ - key: TValue - label: string - }> - isLoading?: boolean - isDisabled?: boolean - autoFocus?: boolean - className?: ComponentProps<'div'>['className'] - allowEmpty?: boolean -}) { - const [open, setOpen] = useState(false) - const [rawQuery, setRawQuery] = useState("") - const [currentOptions, setCurrentOptions] = useState(props.options) - const currentOption = props.options?.find(x => (x.key === (props.value ?? props.defaultValue))) - - useEffect(() => { - debounce({ - function: () => { - setCurrentOptions(props.options.filter(x => x.label.toLowerCase().includes(rawQuery.toLowerCase()))) - } - }) - }, [rawQuery]) - - return ( - - - - - { - (open === false) - ? (null) - : ( - -
- setRawQuery(e.currentTarget.value)} - /> -
-
- { - (props.isLoading === false) - ? (null) - : ( - - ) - } - { - (props.options.length > 0) - ? (null) - : ( - - ) - } - - {(option) => { - return ( -
{ - if (props.isDisabled) return - if ((props.allowEmpty === true) && (option.key === props.value)) { - props.onChange(undefined) - setOpen(false) - return - } - props.onChange(option.key) - setOpen(false) - }} - className={cn( - "w-full h-fit flex justify-between items-center gap-2 p-2 cursor-pointer", - (currentOption?.key === option.key) ? "bg-neutral/5" : "bg-none hover:bg-neutral/5" - )} - > - - {option.label} - - -
- ) - }} -
-
-
- )} -
- ) -} + +import { Button } from "@arrhes/ui" +import { css, cx } from "@arrhes/ui/utilities/cn.js" +import { IconCheck, IconChevronDown } from "@tabler/icons-react" +import { ComponentProps, useEffect, useState } from "react" +import { FieldError } from "react-hook-form" +import { FormatNull } from "../../components/formats/formatNull.js" +import { CircularLoader } from "../../components/layouts/circularLoader.js" +import { Virtualizer } from "../../components/layouts/virtualizer.js" +import { Popover } from "../../components/overlays/popover/popover.js" +import { debounce } from "../../utilities/debounce.js" + + +export function InputCombobox(props: { + error?: FieldError + placeholder?: string + value?: TValue | null + defaultValue?: TValue | null + onChange: (value?: TValue | null) => void + options: Array<{ + key: TValue + label: string + }> + isLoading?: boolean + isDisabled?: boolean + autoFocus?: boolean + className?: ComponentProps<'div'>['className'] + allowEmpty?: boolean +}) { + const [open, setOpen] = useState(false) + const [rawQuery, setRawQuery] = useState("") + const [currentOptions, setCurrentOptions] = useState(props.options) + const currentOption = props.options?.find(x => (x.key === (props.value ?? props.defaultValue))) + + useEffect(() => { + debounce({ + function: () => { + setCurrentOptions(props.options.filter(x => x.label.toLowerCase().includes(rawQuery.toLowerCase()))) + } + }) + }, [rawQuery]) + + return ( + + + + + { + (open === false) + ? (null) + : ( + +
+ setRawQuery(e.currentTarget.value)} + /> +
+
+ { + (props.isLoading === false) + ? (null) + : ( + + ) + } + { + (props.options.length > 0) + ? (null) + : ( + + ) + } + + {(option) => { + return ( +
{ + if (props.isDisabled) return + if ((props.allowEmpty === true) && (option.key === props.value)) { + props.onChange(undefined) + setOpen(false) + return + } + props.onChange(option.key) + setOpen(false) + }} + className={cx( + css({ + width: "100%", + height: "fit-content", + display: "flex", + justifyContent: "space-between", + alignItems: "center", + gap: "2", + padding: "1rem", + cursor: "pointer" + }), + (currentOption?.key === option.key) ? css({ backgroundColor: "neutral/5" }) : css({ backgroundColor: "none", _hover: { backgroundColor: "neutral/5" } }) + )} + > + + {option.label} + + +
+ ) + }} +
+
+
+ )} +
+ ) +} diff --git a/packages/platform/src/components/inputs/inputComboboxMultiple.tsx b/packages/dashboard/src/components/inputs/inputComboboxMultiple.tsx similarity index 57% rename from packages/platform/src/components/inputs/inputComboboxMultiple.tsx rename to packages/dashboard/src/components/inputs/inputComboboxMultiple.tsx index 740f59d..73af1d7 100644 --- a/packages/platform/src/components/inputs/inputComboboxMultiple.tsx +++ b/packages/dashboard/src/components/inputs/inputComboboxMultiple.tsx @@ -1,170 +1,186 @@ -import { Button } from "#/components/buttons/button.js" -import { ButtonGhost } from "#/components/buttons/buttonGhost.js" -import { FormatNull } from "#/components/formats/formatNull.js" -import { CircularLoader } from "#/components/layouts/circularLoader.js" -import { Command, CommandInput, CommandItem, CommandList } from "#/components/layouts/command.js" -import { Popover } from "#/components/overlays/popover/popover.js" -import { cn } from "#/utilities/cn.js" -import { IconCheck, IconSelector, IconX } from "@tabler/icons-react" -import { CommandEmpty, CommandLoading } from "cmdk" -import { Fragment, useState } from "react" - - - -type InputComboboxMultiple = { - placeholder: string - emptyLabel?: string - options: Array<{ - key: TValue - label: string - }> - selectedOptions: Array<{ - key: TValue - label: string - }> - onChange: (newValues: Array<{ - key: TValue - label: string - }>) => void - className?: string - autoFocus?: boolean - loading?: boolean - isDisabled?: boolean -} - -export function InputComboboxMultiple(props: InputComboboxMultiple) { - - const [open, setOpen] = useState(false) - - const handleUnselect = (index: number) => props.onChange([...props.selectedOptions.slice(0, index), ...props.selectedOptions.slice(index + 1)]) - - const options = props.options - .filter((option) => !props.selectedOptions.some((x) => x.key === option.key)) - - return ( -
-
- {(props.selectedOptions.length === 0) ? ( -
- -
- ) : ( - props.selectedOptions.map((option, index) => ( - -
- - {option.label} - - handleUnselect(index)} - icon={} - /> -
-
- )) - )} -
- - - - - { - !open ? null : ( - - { - const option = options?.find(x => x.key === value)?.label.toLowerCase() - if (option?.includes(search.toLowerCase())) return 1 - return 0 - }} - > - - { - (props.loading === true) - ? ( - - - - ) - : (null) - } - - -
- - No result - -
-
- { - options.map((option) => { - const isSelected = !!props.selectedOptions.find((x) => x.key === option.key) - return ( - { - if (props.isDisabled) return - props.onChange( - isSelected - ? props.selectedOptions.filter((x) => x.key !== option.key) - : [...props.selectedOptions, option] - ) - setOpen(false) - }} - className={cn( - "p-3 h-[40px] flex justify-between items-center overflow-auto gap-3", - isSelected ? "bg-neutral/10" : "bg-none hover:bg-neutral/5" - )} - > - - {option.label} - - - - ) - }) - } -
-
-
- )} -
-
- ) -} +import { Button, ButtonContent } from "@arrhes/ui" +import { css, cx } from "@arrhes/ui/utilities/cn.js" +import { IconCheck, IconSelector, IconX } from "@tabler/icons-react" +import { CommandEmpty, CommandLoading } from "cmdk" +import { Fragment, useState } from "react" +import { FormatNull } from "../../components/formats/formatNull.js" +import { CircularLoader } from "../../components/layouts/circularLoader.js" +import { Command, CommandInput, CommandItem, CommandList } from "../../components/layouts/command.js" +import { Popover } from "../../components/overlays/popover/popover.js" + + + +type InputComboboxMultiple = { + placeholder: string + emptyLabel?: string + options: Array<{ + key: TValue + label: string + }> + selectedOptions: Array<{ + key: TValue + label: string + }> + onChange: (newValues: Array<{ + key: TValue + label: string + }>) => void + className?: string + autoFocus?: boolean + loading?: boolean + isDisabled?: boolean +} + +export function InputComboboxMultiple(props: InputComboboxMultiple) { + + const [open, setOpen] = useState(false) + + const handleUnselect = (index: number) => props.onChange([...props.selectedOptions.slice(0, index), ...props.selectedOptions.slice(index + 1)]) + + const options = props.options + .filter((option) => !props.selectedOptions.some((x) => x.key === option.key)) + + return ( +
+
+ {(props.selectedOptions.length === 0) ? ( +
+ +
+ ) : ( + props.selectedOptions.map((option, index) => ( + +
+ + {option.label} + + +
+
+ )) + )} +
+ + + + + { + !open ? null : ( + + { + const option = options?.find(x => x.key === value)?.label.toLowerCase() + if (option?.includes(search.toLowerCase())) return 1 + return 0 + }} + > + + { + (props.loading === true) + ? ( + + + + ) + : (null) + } + + +
+ + No result + +
+
+ { + options.map((option) => { + const isSelected = !!props.selectedOptions.find((x) => x.key === option.key) + return ( + { + if (props.isDisabled) return + props.onChange( + isSelected + ? props.selectedOptions.filter((x) => x.key !== option.key) + : [...props.selectedOptions, option] + ) + setOpen(false) + }} + className={cx( + css({ + padding: "3", + height: "[40px]", + display: "flex", + justifyContent: "space-between", + alignItems: "center", + overflowY: "auto", + gap: "3" + }), + isSelected ? css({ backgroundColor: "neutral/10" }) : css({ backgroundColor: "none", _hover: { backgroundColor: "neutral/5" } }) + )} + > + + {option.label} + + + + ) + }) + } +
+
+
+ )} +
+
+ ) +} diff --git a/packages/platform/src/components/inputs/inputDataCombobox.tsx b/packages/dashboard/src/components/inputs/inputDataCombobox.tsx similarity index 81% rename from packages/platform/src/components/inputs/inputDataCombobox.tsx rename to packages/dashboard/src/components/inputs/inputDataCombobox.tsx index 13586fa..71ff466 100644 --- a/packages/platform/src/components/inputs/inputDataCombobox.tsx +++ b/packages/dashboard/src/components/inputs/inputDataCombobox.tsx @@ -1,39 +1,39 @@ -import { InputCombobox } from "#/components/inputs/inputCombobox.js" -import { useHTTPData } from "#/utilities/useHTTPData.js" -import { routeDefinition } from "@arrhes/metadata/utilities" -import * as v from "valibot" - - -export function InputDataCombobox< - TRouteDefinition extends ReturnType ->(props: { - routeDefinition: TRouteDefinition - body: v.InferInput - placeholder?: string - getOption: (data: v.InferOutput[number]) => ({ key: string, label: string }) - value?: string | null - onChange: (value?: string | null) => void -}) { - const response = useHTTPData({ - routeDefinition: props.routeDefinition, - body: props.body, - }) - - return ( - props.getOption(item)) - : [props.getOption(response.data)] - } - /> - ) -} +import { InputCombobox } from "../../components/inputs/inputCombobox.js" +import { useDataFromAPI } from "../../utilities/useHTTPData.js" +import { routeDefinition } from "@arrhes/application-metadata/utilities" +import * as v from "valibot" + + +export function InputDataCombobox< + TRouteDefinition extends ReturnType +>(props: { + routeDefinition: TRouteDefinition + body: v.InferInput + placeholder?: string + getOption: (data: v.InferOutput[number]) => ({ key: string, label: string }) + value?: string | null + onChange: (value?: string | null) => void +}) { + const response = useDataFromAPI({ + routeDefinition: props.routeDefinition, + body: props.body, + }) + + return ( + props.getOption(item)) + : [props.getOption(response.data)] + } + /> + ) +} diff --git a/packages/platform/src/components/inputs/inputDate.tsx b/packages/dashboard/src/components/inputs/inputDate.tsx similarity index 71% rename from packages/platform/src/components/inputs/inputDate.tsx rename to packages/dashboard/src/components/inputs/inputDate.tsx index d3907d7..06de3be 100644 --- a/packages/platform/src/components/inputs/inputDate.tsx +++ b/packages/dashboard/src/components/inputs/inputDate.tsx @@ -1,88 +1,104 @@ -import { cn } from "#/utilities/cn.js" -import { InputHTMLAttributes } from "react" -import { FieldError } from "react-hook-form" -import { IMask, IMaskInput } from "react-imask" - - -export function InputDate(props: - & Omit, "defaultValue" | "value" | "onChange"> - & { - error?: FieldError - defaultValue?: string | undefined | null - value?: string | undefined | null - onChange: (value: string | undefined) => void - } -) { - - function input(value: string | undefined | null) { - if (!value) return undefined - if (String(new Date(value)) === "Invalid Date") return undefined - - let date = new Date(value) - let day = String(date.getDate()) - let month = String(date.getMonth() + 1) - let year = String(date.getFullYear()) - - if (date.getDate() < 10) day = "0" + day - if ((date.getMonth() + 1) < 10) month = "0" + month - return [day, month, year].join(' / ') - } - - function output(value: string | undefined) { - if (!value) return undefined - const yearMonthDay = value.split(' / ') - return new Date(Number(yearMonthDay[2]), Number(yearMonthDay[1]) - 1, Number(yearMonthDay[0]), 12, 0, 0)?.toISOString() - } - - return ( -
- props.onChange(output(String(value)))} - value={input(props.value)} - className={cn( - "rounded-[inherit] w-full text-sm placeholder:text-neutral/25 p-2", - "overflow-hidden whitespace-nowrap text-ellipsis", - )} - inputMode="decimal" - /> -
- ) -} +import { css, cx } from "@arrhes/ui/utilities/cn.js" +import { InputHTMLAttributes } from "react" +import { FieldError } from "react-hook-form" +import { IMask, IMaskInput } from "react-imask" + + +export function InputDate(props: + & Omit, "defaultValue" | "value" | "onChange"> + & { + error?: FieldError + defaultValue?: string | undefined | null + value?: string | undefined | null + onChange: (value: string | undefined) => void + } +) { + + function input(value: string | undefined | null) { + if (!value) return undefined + if (String(new Date(value)) === "Invalid Date") return undefined + + let date = new Date(value) + let day = String(date.getDate()) + let month = String(date.getMonth() + 1) + let year = String(date.getFullYear()) + + if (date.getDate() < 10) day = "0" + day + if ((date.getMonth() + 1) < 10) month = "0" + month + return [day, month, year].join(' / ') + } + + function output(value: string | undefined) { + if (!value) return undefined + const yearMonthDay = value.split(' / ') + return new Date(Number(yearMonthDay[2]), Number(yearMonthDay[1]) - 1, Number(yearMonthDay[0]), 12, 0, 0)?.toISOString() + } + + return ( +
+ props.onChange(output(String(value)))} + value={input(props.value)} + className={css({ + borderRadius: "inherit", + width: "100%", + fontSize: "sm", + _placeholder: { color: "neutral/25" }, + padding: "1rem", + overflow: "hidden", + whiteSpace: "nowrap", + textOverflow: "ellipsis" + })} + inputMode="decimal" + /> +
+ ) +} diff --git a/packages/platform/src/components/inputs/inputDebounced.tsx b/packages/dashboard/src/components/inputs/inputDebounced.tsx similarity index 100% rename from packages/platform/src/components/inputs/inputDebounced.tsx rename to packages/dashboard/src/components/inputs/inputDebounced.tsx diff --git a/packages/dashboard/src/components/inputs/inputDisabled.tsx b/packages/dashboard/src/components/inputs/inputDisabled.tsx new file mode 100644 index 0000000..f3f2f5c --- /dev/null +++ b/packages/dashboard/src/components/inputs/inputDisabled.tsx @@ -0,0 +1,37 @@ +import { css, cx } from "@arrhes/ui/utilities/cn.js" +import { InputHTMLAttributes, useRef } from 'react' +import { FieldError } from 'react-hook-form' + + +type InputDisabled = Omit, "value" | "onChange"> & { + error?: FieldError + value?: string | null + onChange?: (value?: string | null | undefined) => void +} + +export function InputDisabled(props: InputDisabled) { + const ref = useRef(null) + return ( + + ) +} diff --git a/packages/platform/src/components/inputs/inputFile.tsx b/packages/dashboard/src/components/inputs/inputFile.tsx similarity index 61% rename from packages/platform/src/components/inputs/inputFile.tsx rename to packages/dashboard/src/components/inputs/inputFile.tsx index 70279f5..e118854 100644 --- a/packages/platform/src/components/inputs/inputFile.tsx +++ b/packages/dashboard/src/components/inputs/inputFile.tsx @@ -1,53 +1,72 @@ -import { Button } from "#/components/buttons/button.js" -import { InputHTMLAttributes, useRef } from 'react' -import { FieldError } from 'react-hook-form' - - -export function InputFile(props: - & Omit, "value" | "onChange"> & { - error?: FieldError - value?: File | null - onChange?: (value?: File | null | undefined) => void - type?: "image" - } -) { - const inputRef = useRef(null) - - // useImperativeHandle(props.ref, () => inputRef.current as HTMLInputElement) - - return ( -
{ - event.preventDefault() - if (!props.onChange) return - if (event.dataTransfer.files) { - props.onChange(event.dataTransfer.files[0]) - } - }} - onDragOver={(event) => event.preventDefault()} - > - { - if (!props.onChange) return - if (event.target.files) { - props.onChange(event.target.files[0]) - } - }} - accept={!props.type ? "*" : "image/*"} - className="hidden w-full h-full" - /> - -
- ) -} +import { Button } from "@arrhes/ui" +import { css } from "@arrhes/ui/utilities/cn.js" +import { InputHTMLAttributes, useRef } from 'react' +import { FieldError } from 'react-hook-form' + + +export function InputFile(props: + & Omit, "value" | "onChange"> & { + error?: FieldError + value?: File | null + onChange?: (value?: File | null | undefined) => void + type?: "image" + } +) { + const inputRef = useRef(null) + + // useImperativeHandle(props.ref, () => inputRef.current as HTMLInputElement) + + return ( +
{ + event.preventDefault() + if (!props.onChange) return + if (event.dataTransfer.files) { + props.onChange(event.dataTransfer.files[0]) + } + }} + onDragOver={(event) => event.preventDefault()} + > + { + if (!props.onChange) return + if (event.target.files) { + props.onChange(event.target.files[0]) + } + }} + accept={!props.type ? "*" : "image/*"} + className={css({ display: "none", width: "100%", height: "100%" })} + /> + +
+ ) +} diff --git a/packages/platform/src/components/inputs/inputNumber.tsx b/packages/dashboard/src/components/inputs/inputNumber.tsx similarity index 62% rename from packages/platform/src/components/inputs/inputNumber.tsx rename to packages/dashboard/src/components/inputs/inputNumber.tsx index 8541cbd..ec5ded3 100644 --- a/packages/platform/src/components/inputs/inputNumber.tsx +++ b/packages/dashboard/src/components/inputs/inputNumber.tsx @@ -1,62 +1,77 @@ -import { cn } from "#/utilities/cn.js" -import { InputHTMLAttributes } from "react" -import { FieldError } from "react-hook-form" -import { IMask, IMaskInput } from 'react-imask' - - -export function InputPrice(props: - & Omit, "defaultValue" | "value" | "onChange"> - & { - error?: FieldError - defaultValue?: string | undefined | null - value?: string | undefined | null - onChange: (value: string | undefined) => void - } -) { - - function input(value: string | undefined | null) { - if (value === null || value === undefined) return undefined - return value - } - - function output(value: string | undefined) { - if (value === undefined) return value - return value - } - - return ( -
- { event.currentTarget.select() }} - // onFocus={(event) => { event.currentTarget.setSelectionRange(-1, -1) }} - onAccept={(value: unknown) => props.onChange(output(String(value)))} - value={input(props.value)} - className={cn( - "rounded-[inherit] w-full text-base placeholder:text-neutral/25 p-2", - "focus:shadow-inner focus:bg-neutral/5", - "overflow-hidden whitespace-nowrap text-ellipsis" - )} - inputMode="decimal" - /> -
- - ) -} +import { css, cx } from "@arrhes/ui/utilities/cn.js" +import { InputHTMLAttributes } from "react" +import { FieldError } from "react-hook-form" +import { IMask, IMaskInput } from 'react-imask' + + +export function InputPrice(props: + & Omit, "defaultValue" | "value" | "onChange"> + & { + error?: FieldError + defaultValue?: string | undefined | null + value?: string | undefined | null + onChange: (value: string | undefined) => void + } +) { + + function input(value: string | undefined | null) { + if (value === null || value === undefined) return undefined + return value + } + + function output(value: string | undefined) { + if (value === undefined) return value + return value + } + + return ( +
+ { event.currentTarget.select() }} + // onFocus={(event) => { event.currentTarget.setSelectionRange(-1, -1) }} + onAccept={(value: unknown) => props.onChange(output(String(value)))} + value={input(props.value)} + className={css({ + borderRadius: "inherit", + width: "100%", + fontSize: "base", + _placeholder: { color: "neutral/25" }, + padding: "1rem", + _focus: { boxShadow: "inset", backgroundColor: "neutral/5" }, + overflow: "hidden", + whiteSpace: "nowrap", + textOverflow: "ellipsis" + })} + inputMode="decimal" + /> +
+ + ) +} diff --git a/packages/platform/src/components/inputs/inputPassword.tsx b/packages/dashboard/src/components/inputs/inputPassword.tsx similarity index 55% rename from packages/platform/src/components/inputs/inputPassword.tsx rename to packages/dashboard/src/components/inputs/inputPassword.tsx index ffd64c2..00561b9 100644 --- a/packages/platform/src/components/inputs/inputPassword.tsx +++ b/packages/dashboard/src/components/inputs/inputPassword.tsx @@ -1,60 +1,79 @@ -import { Button } from "#/components/buttons/button.js" -import { cn } from "#/utilities/cn.js" -import { IconEye, IconEyeClosed } from '@tabler/icons-react' -import { InputHTMLAttributes, forwardRef, useState } from 'react' -import { FieldError } from 'react-hook-form' - - -type InputPassword = Omit, "value" | "onChange"> & { - error?: FieldError - value?: string | null - onChange: (value?: string | null | undefined) => void - autoFocus?: boolean -} - -export const InputPassword = forwardRef( - function (props, ref) { - const [showPassword, setShowPassword] = useState(false) - const handleClickShowPassword = () => setShowPassword((show) => !show) - - function input(value: string | undefined | null) { - if (!value) return "" - return value - } - - function output(value: string) { - if (!value) return null - return value - } - - return ( -
- props.onChange(output(e.currentTarget.value))} - autoFocus={props.autoFocus} - /> - -
- ) - } -) +import { Button } from "@arrhes/ui" +import { css, cx } from "@arrhes/ui/utilities/cn.js" +import { IconEye, IconEyeClosed } from '@tabler/icons-react' +import { InputHTMLAttributes, forwardRef, useState } from 'react' +import { FieldError } from 'react-hook-form' + + +type InputPassword = Omit, "value" | "onChange"> & { + error?: FieldError + value?: string | null + onChange: (value?: string | null | undefined) => void + autoFocus?: boolean +} + +export const InputPassword = forwardRef( + function (props, ref) { + const [showPassword, setShowPassword] = useState(false) + const handleClickShowPassword = () => setShowPassword((show) => !show) + + function input(value: string | undefined | null) { + if (!value) return "" + return value + } + + function output(value: string) { + if (!value) return null + return value + } + + return ( +
+ props.onChange(output(e.currentTarget.value))} + autoFocus={props.autoFocus} + /> + +
+ ) + } +) diff --git a/packages/platform/src/components/inputs/inputRating.tsx b/packages/dashboard/src/components/inputs/inputRating.tsx similarity index 68% rename from packages/platform/src/components/inputs/inputRating.tsx rename to packages/dashboard/src/components/inputs/inputRating.tsx index 37acfec..224b70e 100644 --- a/packages/platform/src/components/inputs/inputRating.tsx +++ b/packages/dashboard/src/components/inputs/inputRating.tsx @@ -1,53 +1,57 @@ -import { cn } from "#/utilities/cn.js" -import { IconStarFilled } from '@tabler/icons-react' -import { InputHTMLAttributes, forwardRef } from 'react' -import { FieldError } from 'react-hook-form' - - -type InputText = Omit, "value" | "onChange"> & { - error?: FieldError - value?: number | null - onChange?: (value?: number | null | undefined) => void -} - -export const InputRating = forwardRef( - function (props, ref) { - - function input(value: number | undefined | null) { - if (!value) return 0 - return value - } - - function output(value: number) { - if (value === 0) return undefined - return value - } - - return ( -
- - {Array(5) - .fill(0) - .map((_, i) => ( -
{ - if (!props.onChange) return - props?.onChange(output((i === +input(props.value) - 1) ? 0 : i + 1)) - } - } - > - -
- ))} -
- ) - } -) +import { css, cx } from "@arrhes/ui/utilities/cn.js" +import { IconStarFilled } from '@tabler/icons-react' +import { InputHTMLAttributes, forwardRef } from 'react' +import { FieldError } from 'react-hook-form' + + +type InputText = Omit, "value" | "onChange"> & { + error?: FieldError + value?: number | null + onChange?: (value?: number | null | undefined) => void +} + +export const InputRating = forwardRef( + function (props, ref) { + + function input(value: number | undefined | null) { + if (!value) return 0 + return value + } + + function output(value: number) { + if (value === 0) return undefined + return value + } + + return ( +
+ + {Array(5) + .fill(0) + .map((_, i) => ( +
{ + if (!props.onChange) return + props?.onChange(output((i === +input(props.value) - 1) ? 0 : i + 1)) + } + } + > + +
+ ))} +
+ ) + } +) diff --git a/packages/dashboard/src/components/inputs/inputSelect.tsx b/packages/dashboard/src/components/inputs/inputSelect.tsx new file mode 100644 index 0000000..3071126 --- /dev/null +++ b/packages/dashboard/src/components/inputs/inputSelect.tsx @@ -0,0 +1,207 @@ +import { Button } from "@arrhes/ui" +import { css, cx } from "@arrhes/ui/utilities/cn.js" +import { IconCheck, IconChevronDown } from "@tabler/icons-react" +import { InputHTMLAttributes, useState } from 'react' +import { FieldError } from 'react-hook-form' +import { FormatNull } from "../../components/formats/formatNull.js" +import { CircularLoader } from "../../components/layouts/circularLoader.js" +import { Popover } from "../../components/overlays/popover/popover.js" + + +export function InputSelect(props: + & Omit, "value" | "onChange"> + & { + error?: FieldError + value?: TValue | null + defaultValue?: TValue | null + onChange?: (value?: TValue | null | undefined) => void + options: Array<{ + key: TValue + label: string + }> | undefined + autoFocus?: boolean + allowEmpty?: boolean + isDisabled?: boolean + isLoading?: boolean + } +) { + const [open, setOpen] = useState(false) + + function input(value: TValue | null | undefined) { + return value + } + + function output(value: TValue | undefined | null) { + if (!value) return null + return value + } + + const currentOption = props.options?.find(x => x.key === input(props.value ?? props.defaultValue)) + return ( + + + + + +
+ { + (props.isLoading === true) + ? ( + + ) + : (props.options === undefined || props.options.length === 0) + ? ( + + ) + : props.options.map((option) => ( +
{ + if (props.isDisabled === true) return + if (props.onChange === undefined) return + if ((props.allowEmpty === true) && (option.key === props.value)) { + props.onChange(undefined) + setOpen(false) + return + } + props.onChange(output(option.key)) + setOpen(false) + }} + className={cx( + css({ + position: "relative", + width: "100%", + display: "flex", + justifyContent: "space-between", + alignItems: "center", + gap: "2", + padding: "1rem", + borderRadius: "sm", + border: "1px solid transparent", + cursor: "pointer" + }), + css(option.key === props.value + ? { backgroundColor: "neutral/5", borderColor: "neutral/5" } + : { backgroundColor: "none", _hover: { backgroundColor: "neutral/5", borderColor: "neutral/5" } } + ) + )} + > + + {option.label} + + +
+ )) + } +
+
+
+ ) +} diff --git a/packages/dashboard/src/components/inputs/inputSwitch.tsx b/packages/dashboard/src/components/inputs/inputSwitch.tsx new file mode 100644 index 0000000..74be3b7 --- /dev/null +++ b/packages/dashboard/src/components/inputs/inputSwitch.tsx @@ -0,0 +1,64 @@ + +import { css, cx } from "@arrhes/ui/utilities/cn.js" +import * as SwitchPrimitives from "@radix-ui/react-switch" +import { ComponentProps } from "react" + + +type InputSwitch = Omit, "value" | "onChange"> & { + value: boolean + onChange: (value: boolean) => void +} + +export function InputSwitch(props: InputSwitch) { + function input(value: boolean | undefined | null) { + if (!value) return false + return value + } + + function output(value: boolean) { + return value + } + + return ( + props.onChange(output(checked))} + autoFocus={props.autoFocus} + > + + + ) +} diff --git a/packages/dashboard/src/components/inputs/inputText.tsx b/packages/dashboard/src/components/inputs/inputText.tsx new file mode 100644 index 0000000..a55f88d --- /dev/null +++ b/packages/dashboard/src/components/inputs/inputText.tsx @@ -0,0 +1,62 @@ +import { css, cx } from "@arrhes/ui/utilities/cn.js" +import { InputHTMLAttributes } from 'react' +import { FieldError } from 'react-hook-form' + + +type InputText = Omit, "value" | "onChange"> & { + error?: FieldError + value?: string | null | undefined + onChange?: (value?: string | null | undefined) => void +} + +export function InputText(props: InputText) { + function input(value: string | undefined | null) { + if (!value) return "" + return value + } + + function output(value: string | undefined | null) { + if (!value) return null + return value + } + + return ( +
+ { + if (!props.onChange) return + props?.onChange(output(e.currentTarget.value)) + }} + /> +
+ ) +} \ No newline at end of file diff --git a/packages/platform/src/components/inputs/inputTextArea.tsx b/packages/dashboard/src/components/inputs/inputTextArea.tsx similarity index 56% rename from packages/platform/src/components/inputs/inputTextArea.tsx rename to packages/dashboard/src/components/inputs/inputTextArea.tsx index fa75cee..c38c56f 100644 --- a/packages/platform/src/components/inputs/inputTextArea.tsx +++ b/packages/dashboard/src/components/inputs/inputTextArea.tsx @@ -1,48 +1,64 @@ -import { cn } from "#/utilities/cn.js" -import { ComponentPropsWithRef, useRef } from 'react' -import { FieldError } from 'react-hook-form' - - -export function InputTextArea(props: - & Omit, "value" | "onChange"> - & { - error?: FieldError - value?: string | null - onChange: (value?: string | null | undefined) => void - } -) { - const textAreaRef = useRef(null) - - function input(value: string | undefined | null) { - if (!value) return "" - return value - } - - function output(value: string) { - if (!value) return null - return value - } - - return ( -