Rebrand: rename ondeck->horizon in package.json, docker-compose, SERVER.md, docs; production stack at /opt/stacks/horizon
This commit is contained in:
parent
77f23e12cd
commit
bbdbe1ddc0
8 changed files with 464 additions and 46 deletions
|
|
@ -17,22 +17,39 @@ tail -f /var/log/horizon.log
|
|||
```
|
||||
|
||||
## Details
|
||||
- **Port:** 3000 (proxied via Pangolin/Nginx to https://horizon.seubert.cloud)
|
||||
- **Working directory:** `/opt/projects/OnDeck/ondeck`
|
||||
- **Mode:** `npm run dev` (Next.js with Turbopack)
|
||||
- **Service file:** `/etc/systemd/system/horizon.service`
|
||||
- **Port:** 3000 (proxied via Pangolin to https://horizon.seubert.cloud)
|
||||
- **Stack directory:** `/opt/stacks/horizon`
|
||||
- **Mode:** Docker Compose (production Next.js standalone build)
|
||||
- **Container names:** `horizon-app`, `horizon-db`
|
||||
|
||||
## After code changes
|
||||
Changes hot-reload automatically. If the server gets into a bad state:
|
||||
## Managing the container stack
|
||||
```bash
|
||||
systemctl restart horizon
|
||||
cd /opt/stacks/horizon
|
||||
docker compose pull && docker compose up -d --build # rebuild & restart
|
||||
docker compose restart horizon-app # restart app only
|
||||
docker compose down # stop all
|
||||
docker compose logs -f horizon-app # app logs
|
||||
docker compose logs -f horizon-db # db logs
|
||||
```
|
||||
|
||||
## After code changes (rebuild image)
|
||||
```bash
|
||||
cd /opt/stacks/horizon
|
||||
docker compose up -d --build horizon-app
|
||||
```
|
||||
|
||||
## After schema changes
|
||||
Run these before restarting:
|
||||
```bash
|
||||
cd /opt/projects/OnDeck/ondeck
|
||||
npx prisma db push
|
||||
npx prisma generate
|
||||
systemctl restart horizon
|
||||
cd /opt/stacks/horizon
|
||||
docker compose exec horizon-app npx prisma db push
|
||||
docker compose restart horizon-app
|
||||
```
|
||||
|
||||
## Dev server (local development only)
|
||||
The systemd dev service still runs at `/opt/projects/OnDeck/ondeck`:
|
||||
```bash
|
||||
systemctl start horizon # start dev
|
||||
systemctl stop horizon # stop dev
|
||||
systemctl restart horizon # restart dev
|
||||
systemctl status horizon # check status
|
||||
```
|
||||
|
|
|
|||
|
|
@ -1,16 +1,17 @@
|
|||
version: '3.8'
|
||||
|
||||
services:
|
||||
app:
|
||||
horizon-app:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
container_name: horizon-app
|
||||
ports:
|
||||
- "3000:3000"
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
- DATABASE_URL=postgresql://ondeck_user:ondeck_password_2026!@db:5432/ondeck
|
||||
- NEXTAUTH_URL=http://localhost:3000
|
||||
- DATABASE_URL=postgresql://horizon_user:${DB_PASSWORD}@horizon-db:5432/horizon
|
||||
- NEXTAUTH_URL=${NEXTAUTH_URL}
|
||||
- NEXTAUTH_SECRET=${NEXTAUTH_SECRET}
|
||||
- AZURE_AD_CLIENT_ID=${AZURE_AD_CLIENT_ID}
|
||||
- AZURE_AD_CLIENT_SECRET=${AZURE_AD_CLIENT_SECRET}
|
||||
|
|
@ -19,35 +20,43 @@ services:
|
|||
- AFW_DATABASE=${AFW_DATABASE}
|
||||
- AFW_USER=${AFW_USER}
|
||||
- AFW_PASSWORD=${AFW_PASSWORD}
|
||||
- CRON_SECRET=${CRON_SECRET}
|
||||
- METRICS_SECRET=${METRICS_SECRET}
|
||||
- GRAPH_CLIENT_ID=${GRAPH_CLIENT_ID}
|
||||
- GRAPH_CLIENT_SECRET=${GRAPH_CLIENT_SECRET}
|
||||
- GRAPH_TENANT_ID=${GRAPH_TENANT_ID}
|
||||
depends_on:
|
||||
- db
|
||||
horizon-db:
|
||||
condition: service_healthy
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- ondeck-network
|
||||
- horizon-internal
|
||||
- pangolin
|
||||
|
||||
db:
|
||||
horizon-db:
|
||||
image: postgres:17
|
||||
container_name: horizon-db
|
||||
environment:
|
||||
- POSTGRES_DB=ondeck
|
||||
- POSTGRES_USER=ondeck_user
|
||||
- POSTGRES_PASSWORD=ondeck_password_2026!
|
||||
ports:
|
||||
- "5432:5432"
|
||||
- POSTGRES_DB=horizon
|
||||
- POSTGRES_USER=horizon_user
|
||||
- POSTGRES_PASSWORD=${DB_PASSWORD}
|
||||
volumes:
|
||||
- ondeck-pgdata:/var/lib/postgresql/data
|
||||
- horizon-pgdata:/var/lib/postgresql/data
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- ondeck-network
|
||||
- horizon-internal
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U ondeck_user -d ondeck"]
|
||||
test: ["CMD-SHELL", "pg_isready -U horizon_user -d horizon"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
volumes:
|
||||
ondeck-pgdata:
|
||||
horizon-pgdata:
|
||||
driver: local
|
||||
|
||||
networks:
|
||||
ondeck-network:
|
||||
horizon-internal:
|
||||
driver: bridge
|
||||
pangolin:
|
||||
external: true
|
||||
|
|
|
|||
|
|
@ -6,11 +6,11 @@ The Designation Admin Interface allows administrators to create and manage clien
|
|||
|
||||
## Key Concepts
|
||||
|
||||
### Designations are Created in OnDeck
|
||||
### Designations are Created in Horizon
|
||||
|
||||
**All designations are created and managed within the OnDeck application.** They are NOT imported from AFW. Instead:
|
||||
**All designations are created and managed within the Horizon application.** They are NOT imported from AFW. Instead:
|
||||
|
||||
1. **Create a designation** in OnDeck (e.g., "Shape", "Premium", "VIP")
|
||||
1. **Create a designation** in Horizon (e.g., "Shape", "Premium", "VIP")
|
||||
2. **Optionally map it to an AFW ANotId** (a GUID that identifies customers in AMS360)
|
||||
3. **Sync to automatically assign** clients based on their AFW data
|
||||
|
||||
|
|
@ -19,12 +19,12 @@ The Designation Admin Interface allows administrators to create and manage clien
|
|||
Each designation can have an **optional AFW ANotId** field:
|
||||
- This is a GUID from AMS360/AFW (e.g., `13CF7DCB-F6AF-42C2-A7AB-26641A216A81`)
|
||||
- It identifies a group of customers in the AFW database
|
||||
- When you sync, clients with this ANotId in AFW get assigned to this designation in OnDeck
|
||||
- When you sync, clients with this ANotId in AFW get assigned to this designation in Horizon
|
||||
|
||||
### Example Workflow
|
||||
|
||||
```
|
||||
1. Admin creates "Shape" designation in OnDeck
|
||||
1. Admin creates "Shape" designation in Horizon
|
||||
- Name: Shape
|
||||
- Color: Indigo
|
||||
- AFW ANotId: 13CF7DCB-F6AF-42C2-A7AB-26641A216A81
|
||||
|
|
@ -35,7 +35,7 @@ Each designation can have an **optional AFW ANotId** field:
|
|||
3. Admin saves the designation
|
||||
|
||||
4. Admin clicks "Sync" on the Shape designation
|
||||
- OnDeck queries AFW for customers with ANotId 13CF7DCB-...
|
||||
- Horizon queries AFW for customers with ANotId 13CF7DCB-...
|
||||
- Finds matching clients in local database
|
||||
- Updates their designationId to "Shape"
|
||||
- Result: 145 clients updated, 5 skipped (already had Shape)
|
||||
|
|
|
|||
|
|
@ -9,14 +9,14 @@
|
|||
|
||||
### What this script does
|
||||
|
||||
This script imports historical SHAPE task completion data from the team's SharePoint Excel files into OnDeck. It is a **one-time migration tool** — not part of the ongoing sync.
|
||||
This script imports historical SHAPE task completion data from the team's SharePoint Excel files into Horizon. It is a **one-time migration tool** — not part of the ongoing sync.
|
||||
|
||||
Each team member has a folder on SharePoint at:
|
||||
```
|
||||
Claims/SHAPE Accounts/{MEMBER_FOLDER}/{Client}.xlsx
|
||||
```
|
||||
|
||||
The script reads every client Excel file for each advocate, matches it to a client in OnDeck, and records whether each SHAPE task was completed, marked N/A, or left blank.
|
||||
The script reads every client Excel file for each advocate, matches it to a client in Horizon, and records whether each SHAPE task was completed, marked N/A, or left blank.
|
||||
|
||||
### Team member folders
|
||||
|
||||
|
|
@ -52,12 +52,12 @@ After running, the report shows:
|
|||
| Stat | Meaning |
|
||||
|---|---|
|
||||
| **Files processed** | Excel files successfully downloaded and parsed |
|
||||
| **Clients matched** | Clients in the Excel that were found in OnDeck |
|
||||
| **Clients matched** | Clients in the Excel that were found in Horizon |
|
||||
| **Clients unmatched** | Clients that could not be matched — need manual review |
|
||||
| **Fuzzy matches** | Clients matched by approximate name — review for correctness |
|
||||
| **Tasks updated** | Existing tasks whose status was set to Completed or N/A |
|
||||
| **Tasks assigned** | Tasks that had the advocate linked to them |
|
||||
| **Tasks created** | Tasks from the Excel that didn't exist in OnDeck yet |
|
||||
| **Tasks created** | Tasks from the Excel that didn't exist in Horizon yet |
|
||||
| **Duplicates deleted** | Extra copies of the same task removed from the DB |
|
||||
| **Ad-hoc created** | "Additional Services" rows and unmatched tasks saved as free-form tasks |
|
||||
| **Advocates assigned** | Clients that had their Claims Advocate set from this import |
|
||||
|
|
@ -65,7 +65,7 @@ After running, the report shows:
|
|||
### What gets skipped
|
||||
|
||||
The script will **not** import a row if:
|
||||
- The client name in the Excel cannot be matched to any OnDeck client (logged as "unmatched")
|
||||
- The client name in the Excel cannot be matched to any Horizon client (logged as "unmatched")
|
||||
- The file is named `archive*`, contains `template`, `master workbook`, or starts with `all shape` — these are intentionally excluded
|
||||
|
||||
Nothing else is filtered. Every task row in every matched client file is processed.
|
||||
|
|
@ -80,9 +80,9 @@ Specifically: if the database already has two identical tasks for the same clien
|
|||
|
||||
After running the dry run, check the **"Unmatched Clients"** section of the report. For each one:
|
||||
|
||||
1. Check if the client exists in OnDeck under a different spelling
|
||||
2. If yes — either rename the client in OnDeck to match, or rename the Excel file
|
||||
3. If no — create the client in OnDeck first, then re-run the import
|
||||
1. Check if the client exists in Horizon under a different spelling
|
||||
2. If yes — either rename the client in Horizon to match, or rename the Excel file
|
||||
3. If no — create the client in Horizon first, then re-run the import
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -116,7 +116,7 @@ Each .xlsx file:
|
|||
4. processFile() × N For each file:
|
||||
└── parseExcelFile() Parse XLSX without external libraries (custom ZIP+XML)
|
||||
└── parseExcelBlocks() Extract client blocks and task rows
|
||||
└── matchClient() Match Excel client name → OnDeck client
|
||||
└── matchClient() Match Excel client name → Horizon client
|
||||
└── processTaskRow() × N For each task row:
|
||||
└── findMatchingTasks() Look up existing task in DB (±5-day window)
|
||||
└── deduplication Delete extras if >1 match
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"name": "ondeck",
|
||||
"name": "horizon",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* SHAPE Historical Data Import Script
|
||||
*
|
||||
* Imports historical task completion data from SharePoint Excel files into OnDeck.
|
||||
* Imports historical task completion data from SharePoint Excel files into Horizon.
|
||||
* Each team member has a folder in Claims/SHAPE Accounts/{MEMBER_FOLDER}/{Client}.xlsx
|
||||
*
|
||||
* Usage:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue