FF&E Reader
Project Overview
FF&E (Furniture, Fixtures & Equipment) schedules are the operational backbone of interior design projects, and small studios still run them in Excel — with unit-conversion errors, no change history, and no spend visibility (pain points validated in interviews with studio owners). FF&E Reader replaces that workflow with a purpose-built SaaS: an Excel-like editing grid, a domain vocabulary defining the legal units and fields for every product category, event-logged edits with version snapshots and rollback, spend dashboards by space, category, and supplier, templated Excel/PDF export, and token-based client sharing with field-level permissions and WeChat integration. The project bridges my architecture background with software engineering — the domain expertise is the moat generic AI tools can't cross. Built as a two-repo system (FastAPI backend, Next.js frontend) through 24 phased builds with acceptance criteria per phase; the backend MVP closes with 88 passing tests. Deployment is pending, and the architecture reserves a clean upgrade path to AI agents without a rewrite.
Tech Stack & Links
Backend
- Python 3.12 + FastAPI — REST API with OpenAPI schema as the single contract
- SQLModel + Alembic on PostgreSQL 16; JWT + bcrypt authentication
- Celery + Redis for background tasks; openpyxl / WeasyPrint for templated Excel and PDF export
- pytest + pytest-asyncio + httpx — 88 tests across the MVP
Frontend
- Next.js 14 App Router + TypeScript strict mode
- AG Grid Community — the Excel-like schedule editor with custom cell editors
- TanStack Query v5 for server state; Zustand + zundo for client state and undo/redo
- Tailwind CSS + shadcn/ui; ECharts dashboards; React Hook Form + Zod
API Contract
- orval — every frontend API type and hook is generated from the backend's openapi.json; hand-written API types are banned
- CI fails when the backend schema and the generated client drift apart
Infra & Ops
- Docker Compose + Caddy (HTTPS reverse proxy); GitHub Actions CI/CD; AWS EC2 deployment target
- Sentry error monitoring; Qiniu object storage for item images
Key Features
Excel-like schedule grid
AG Grid with per-category dynamic columns, custom cell editors, filtering, and full undo/redo — the input experience studios refuse to give up, minus the spreadsheet failure modes.
Domain vocabulary engine
Product categories, their legal units, and their field definitions live as pure JSON consumed by both validation and the grid — the encoded domain expertise that generic AI tools can't match.
Event log and version snapshots
Every edit is an actor-typed event; schedules snapshot into versions with a diff view and typed-confirmation rollback, giving studios the change trail Excel never had.
Validation engine
Severity-grouped rule checks (unit legality, required fields) surface in a drawer with row-level focus; the rule interface is reserved for future AI reviewers.
Spend statistics dashboard
Aggregated consumption by space, category, and supplier rendered as ECharts pies with a budget gauge — the visibility gap studio owners named in interviews.
Sharing and export
Token-based read-only client pages with field-level permissions and WeChat share integration; Excel and PDF exports render from JSON templates with task polling and download.
Algorithm Flow
The system is organized around one invariant: every mutation flows through the same auditable pipeline — Command, event, snapshot — whether a human at the grid or, someday, an agent initiates it.
- 1
Authenticate & Scope
JWT sessions scope users to their projects and schedules; share tokens grant clients field-level read access with no account required.
- 2
Edit via Commands
Grid edits become Command objects — describe, preview, execute, undo — never raw updates; zundo mirrors the undo/redo experience client-side.
- 3
Log & Snapshot
Every executed command appends an actor-typed event; schedules snapshot into numbered versions that can be diffed and rolled back with typed confirmation.
- 4
Validate
The rule engine checks items against the JSON domain vocabulary — legal units per category, required fields — and groups findings by severity for the review drawer.
- 5
Aggregate & Export
Statistics endpoints aggregate spend for the ECharts dashboard; export tasks render templated Excel and PDF in the background with polling and download.
Challenges & Solutions
Problem
The product's endgame is AI agents — photo/PDF/link to structured items, an AI schedule reviewer, WeChat client approvals — but the MVP deliberately ships zero AI features to stay small enough to build and validate. Built naively, the MVP's data model and write paths would need a teardown the day agents arrive; built agent-first, the MVP would never ship. The two-repo split added a second trap: hand-synchronized frontend and backend types rot on every schema change.
What I tried
The tempting shortcut was plain CRUD — direct updates from the grid, hardcoded category rules, types copied across repos by hand. Prototyping that way made the cost visible: no audit trail for edits, no way to attach provenance or confidence to a row, and every backend schema change silently broke the frontend.
Final approach
Six structural constraints enforced from Phase 0: every write operation is a Command object with describe/preview/execute/undo; every business table carries source, confidence, and needs_review columns; the domain vocabulary and export templates are pure JSON, never hardcoded; an LLMClient interface exists as a deliberate stub; a prompts/ directory is reserved; and the event log types its actor as human, AI, or system. The contract problem got automation instead of discipline: orval regenerates the entire typed client from the backend's OpenAPI schema, and CI fails on drift.
Key insight
Agent-ready is not a feature — it is a handful of cheap structural decisions made at day zero. Commands make future AI actions previewable and undoable exactly like human ones; provenance columns make AI-extracted data first-class instead of bolted on; JSON vocabularies mean an agent will read the same rules humans do. The MVP paid almost nothing for any of this, and the agent roadmap now requires extension, not rewrite.