init
This commit is contained in:
129
README.md
Normal file
129
README.md
Normal file
@@ -0,0 +1,129 @@
|
||||
# BizMatch Phase 2 — Broker Workflow App
|
||||
|
||||
Module 1: foundation (Docker Compose, PostgreSQL, schema, migrations, login).
|
||||
Module 2: business scan (NAS -> DB) and the first UI.
|
||||
|
||||
The UI and all domain constants are English.
|
||||
|
||||
## Setup on 192.168.100.99 (Ubuntu 24.04)
|
||||
|
||||
Prerequisite: Docker + Compose plugin (`sudo apt install docker.io docker-compose-v2`).
|
||||
|
||||
```bash
|
||||
# Unpack the project, then:
|
||||
cd bizmatch-app
|
||||
cp .env.example .env # optionally adjust DB_PASSWORD
|
||||
docker compose up -d --build
|
||||
```
|
||||
|
||||
The app applies all migrations on start and then listens on
|
||||
`http://192.168.100.99:8090`.
|
||||
|
||||
> **Upgrading from Module 1:** `001_init.sql` was rewritten in place (German
|
||||
> constants -> English). Applying it needs a fresh database:
|
||||
> `docker compose down -v && docker compose up -d --build`. The DB held no
|
||||
> production data yet, so there is nothing to migrate.
|
||||
|
||||
First smoke test:
|
||||
|
||||
```bash
|
||||
curl http://localhost:8090/api/health
|
||||
# -> {"ok":true}
|
||||
|
||||
# Create the three staff members (adjust the names):
|
||||
curl -X POST localhost:8090/api/staff -H 'content-type: application/json' -d '{"name":"Chris"}'
|
||||
curl -X POST localhost:8090/api/staff -H 'content-type: application/json' -d '{"name":"..."}'
|
||||
```
|
||||
|
||||
## Dev mode (without the app container)
|
||||
|
||||
```bash
|
||||
docker compose up -d db # database only
|
||||
npm install
|
||||
set -a; source .env; set +a
|
||||
npm run dev # tsx watch, migrations run on start
|
||||
|
||||
# second terminal — frontend with hot reload, /api is proxied to :8090
|
||||
cd web && npm install && npm run dev
|
||||
```
|
||||
|
||||
## NAS mount
|
||||
|
||||
Mount it on the host via NFS, e.g. in `/etc/fstab`:
|
||||
|
||||
```
|
||||
<truenas-ip>:/mnt/<pool>/bizmatch /mnt/bizmatch-nas nfs ro,soft,timeo=100 0 0
|
||||
```
|
||||
|
||||
The compose file already passes `NAS_ROOT` (default `/mnt/bizmatch-nas`) into the
|
||||
app container. Write access (NDA filing) comes in module 6 — then replace `ro`
|
||||
with `rw` and limit the permissions to the two write paths.
|
||||
|
||||
### Business directories
|
||||
|
||||
Directly below `NAS_ROOT` there are three status directories; every immediate
|
||||
subdirectory of those is one business. The directory names are configurable
|
||||
(they contain spaces and are treated as opaque strings):
|
||||
|
||||
| Env var | Default | Business status |
|
||||
| ------------------ | -------------- | --------------- |
|
||||
| `NAS_DIR_ACTIVE` | `AAA = ACTIVE` | ACTIVE |
|
||||
| `NAS_DIR_SOLD` | `AAA = SOLD` | SOLD |
|
||||
| `NAS_DIR_INACTIVE` | `AAA = INACTIVE` | INACTIVE |
|
||||
|
||||
The scan is idempotent: existing rows are matched by name and only updated when
|
||||
`nas_path` or `status` changed. Businesses that exist in the DB but no longer on
|
||||
disk are kept and only reported as a warning in the log. A missing configured
|
||||
directory aborts the scan with an error naming the path.
|
||||
|
||||
## Moving to the AI machine (later)
|
||||
|
||||
1. `docker compose down` on .99
|
||||
2. Take a dump: `docker compose exec db pg_dump -U bizmatch bizmatch > backup.sql`
|
||||
3. Copy the project folder to the AI machine, run `docker compose up -d --build`
|
||||
4. Restore the dump: `docker compose exec -T db psql -U bizmatch bizmatch < backup.sql`
|
||||
|
||||
## API (as of module 2)
|
||||
|
||||
| Method | Path | Purpose | Session |
|
||||
| ------ | --------------------------- | ------------------------------------------------ | ------- |
|
||||
| GET | /api/health | liveness incl. DB check | no |
|
||||
| GET | /api/staff | staff list | no |
|
||||
| POST | /api/staff | create staff member `{name}` | no |
|
||||
| POST | /api/login | login via `{staff_id}` → session cookie | no |
|
||||
| GET | /api/me | signed-in staff member | yes |
|
||||
| POST | /api/logout | sign out | yes |
|
||||
| POST | /api/businesses/scan | scan the NAS → `{scanned, inserted, updated, missing}` | yes |
|
||||
| GET | /api/businesses | list `?status=&search=` + counts per status | yes |
|
||||
| GET | /api/businesses/:id | single business incl. `nas_path` | yes |
|
||||
| GET | /api/businesses/:id/files | live directory listing (PDFs first) | yes |
|
||||
|
||||
Everything except health, staff (GET+POST) and login requires the session
|
||||
cookie; without it the API answers `401`.
|
||||
|
||||
## Frontend
|
||||
|
||||
`web/` is a Vite + React + TypeScript app with Tailwind v4 (no router, no state
|
||||
library). Views: login ("Who is working?"), business list (tabs with counts,
|
||||
search, "Scan NAS now") and business detail (status badge, live file list).
|
||||
|
||||
In dev, Vite proxies `/api` to `http://localhost:8090`. In production the
|
||||
Fastify app serves `web/dist` via `@fastify/static` with an SPA fallback to
|
||||
`index.html` for all non-`/api` routes; the Dockerfile builds the frontend in
|
||||
its own stage and copies `web/dist` into the runtime image.
|
||||
|
||||
## Structure
|
||||
|
||||
```
|
||||
migrations/ numbered SQL migrations (001_init.sql = full schema)
|
||||
src/
|
||||
config.ts env configuration
|
||||
db.ts pg pool + query helpers
|
||||
migrate.ts migration runner (transactional, advisory lock)
|
||||
business-scan.ts NAS scan + directory listing
|
||||
server.ts Fastify app (health, staff, login, businesses, static)
|
||||
web/
|
||||
src/api.ts typed API client
|
||||
src/App.tsx session gate + view switch
|
||||
src/views/ Login, Businesses, BusinessDetail
|
||||
```
|
||||
Reference in New Issue
Block a user