59 lines
No EOL
4.4 KiB
Markdown
59 lines
No EOL
4.4 KiB
Markdown
# NGU-Web
|
|
|
|
Website for NGU (Next Generation of Unity), a Unity movement organization with regional chapters in the US and internationally. Full-stack app with a public site and a role-based admin panel.
|
|
|
|
## Stack
|
|
- Frontend: React, TypeScript, Tailwind CSS, React Router, Vite (in `src/`)
|
|
- Backend: Hono on Node.js, SQLite (WAL mode, STRICT tables) via better-sqlite3 / node:sqlite (in `server/`)
|
|
- Package manager: pnpm only (never npm or yarn)
|
|
|
|
## Deployment (production)
|
|
- Ubuntu VPS, nginx reverse proxy, systemd service `ngu-api`
|
|
- App deployed to `/srv/ngu-api`; database at `/var/lib/ngu/ngu.db`
|
|
- Debugging: check `journalctl -u ngu-api -n 40 --no-pager` first. Make sure rsync ran from the repo (not the deployed copy) before restarting the service.
|
|
- Never run commands against the production server or database unless explicitly asked.
|
|
|
|
## Git workflow
|
|
- Remote is a self-hosted Forgejo server, not GitHub. Do not use `gh`.
|
|
- Open pull requests with `tea`: `tea pr create --base main --head <branch> --title "..." --description "..."`
|
|
- Never commit directly to main. Create a branch per change, push it, open a PR.
|
|
- Versions are marked with annotated tags (v1.0, v1.3...). Don't create or move tags unless asked.
|
|
- `server/dev.db` and other `*.db` files are local only and never committed.
|
|
|
|
## How to work in this repo
|
|
- Read the relevant existing files before writing anything. Follow existing patterns exactly: descriptors, field syntax, extension shape, import conventions.
|
|
- Ask questions up front before implementing non-trivial features.
|
|
- Prefer targeted edits when surrounding code is stable; full rewrites only when a component is being substantially reworked.
|
|
- Fix root causes. No redirect shims or workarounds.
|
|
- Keep data logic in the database and presentation logic in code. Make things configurable via constants, not hardcoded in components.
|
|
- Name components for what they do, not what they currently filter.
|
|
|
|
## Project layout
|
|
- All pages use `PageShell.tsx` as the wrapper unless explicitly noted otherwise.
|
|
- Pages live in `src/pages/`; section-level components go in `src/pages/sections/`.
|
|
- `src/data/` holds only hardcoded data shared across multiple section files (e.g. `historyDecades.ts`, map grid). Everything else comes from SQLite.
|
|
- `navConfig.js` is the single source of truth for navigation, routes, and actions (header, footer, pages).
|
|
- `api.js` is the shared caching client used by frontend data hooks.
|
|
- Logos: org logos in `/org-logos/`, event logos in `public/event-logos/`. The `<Logo>` component hides itself on load error.
|
|
|
|
## Rules and gotchas
|
|
- **Role checks must use ladder comparisons, never equality.** Roles rank viewer → editor → admin → superadmin. Use `roleCanWrite(user)` / `roleCanDelete(user)` from `lib/roles` and the minimum-rank helpers (`canWrite`, `canDelete`, `isSuper`, `atLeast`). `role === "admin"` silently excludes higher roles and has caused repeated bugs.
|
|
- **Imports need explicit extensions** (`.ts`, `.tsx`, `.js`) everywhere.
|
|
- **Vite resolves `.js` before `.ts`**, so a `.js` and `.ts` file with the same base name will import the wrong one. Give new hooks distinct names.
|
|
- **Don't use `fallback: EMPTY` in api.js hooks.** It silently returns empty arrays and hides server errors; let the error state surface.
|
|
|
|
## Admin CRUD engine
|
|
Descriptor-driven: `server/admin-crud.js` and `admin-schema.js` (server) and `adminSchema.js` (client) generate SQL and form fields from declarative entity configs. Adding an entity should mean adding a descriptor, not new CRUD code.
|
|
- Child collections are deleted and reinserted wholesale. Unsafe for entities referenced by foreign keys elsewhere.
|
|
- `reindex: false` prevents cross-entity sort order collisions.
|
|
- The `OMIT` sentinel distinguishes unsent fields from deliberate clears.
|
|
- `admin-schema-sync.js` runs at boot and throws if descriptors don't match live `PRAGMA table_info`. If boot fails after a schema change, update the descriptor or migration so they agree.
|
|
- `admin-cli.js` imports `ROLES` and `destroyAllSessionsFor` from `auth.js`. Keep it that way to prevent drift.
|
|
|
|
## Migrations
|
|
- Sequential files: `001_`, `002_`, ...
|
|
- The runner may drop statements after a `BEGIN...END` trigger body. Put each `CREATE VIEW` in its own migration file with no `BEGIN...END` block.
|
|
- `PRAGMA foreign_keys = OFF` must be set outside transactions when cascading constraints are involved.
|
|
|
|
## Integrations
|
|
- Church Center (ngu.churchcenteronline.com): Planning Center embeds for giving and the calendar. |