exceljs last shipped a stable release in October 2023 (4.4.0) and has no repository commits since January 2024, so it no longer meets the dependency maintenance bar. write-excel-file is actively maintained, MIT, Node 18+, and writes to a file path, buffer, or stream, which fits the worker export job and protected volume. CSV stays on PapaParse. read-excel-file is noted as the counterpart if XLSX import is ever required; imports remain CSV-only.
Logos CRM Specifications
Read in this order:
architecture.md— scope, decisions, packages, permissions, and acceptance criteria.data-model.md— PostgreSQL entities, constraints, merge rules, visibility, search, and retention.backend.md— services, API routes, jobs, reporting, security, and tests.frontend.md— screens, interactions, design-system requirements, and browser tests.deployment.md— Docker Compose, Infra contracts, secrets, health, release, and recovery.migration.md— CiviCRM import, reconciliation, cutover, and rollback.
The runtime is intentionally small: one Next.js application image used by web and worker, one PostgreSQL service, one protected file volume, and Infra-provided authentication and SMTP. There is no Redis, hosted queue, Vercel dependency, separate backend service, or separate scheduler.
Implementation is reuse-first: Drizzle owns the persistence schema, browser-safe Zod schemas own API and form contracts, Drizzle Kit owns migrations, and Drizzle Seed owns fixtures; Next.js Route Handlers expose REST endpoints; CASL owns ability evaluation; Graphile Worker owns scheduling and retries; PapaParse and write-excel-file own file formats. CRM-specific code is limited to business rules, queries, and UI composition.
Demo implementation
The logos-crm branch includes a PostgreSQL-backed vertical slice under apps/logos-crm: a pipeline summary, searchable case table, case detail/next-action view, case creation, status progression, people and organisation directories, contact methods, explicit case relationships, record activity timelines, and assigned tasks through Next.js Route Handlers. Activities and tasks each belong to exactly one case, person, or organisation, with that invariant enforced in PostgreSQL. The demo supports recording notes, creating tasks, and completing or reopening tasks. It intentionally omits production authentication, CASL enforcement, Graphile Worker jobs, reminders, notifications, imports, merges, and CiviCRM cutover.
Run the complete demo with docker compose -f apps/logos-crm/compose.yaml up --build. Compose starts PostgreSQL, runs the Drizzle migration and idempotent demo seed, then serves the CRM at http://localhost:3004. The db:migrate, db:seed, and dev workspace scripts remain available for local development.