Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
# WARNING: This file may be outdated
# See ./src/env.ts for the up-to-date required environment variables

# PUBLIC_URL="" # set up this value when deploying on a domain (without trailing slash). default to http://localhost:PORT
# PORT="" # you can change the server port if you want. default to 3000
# TRUSTED_ORIGINS="" # comma-separated list of allowed origins. default to http://localhost:3000,3001,3002,5173,5174,5175

DB_HOST=""
DB_PORT="5432"
Expand All @@ -19,9 +17,6 @@ REDIS_PASSWORD=""
# you generate it with `openssl rand -hex 32` !!! MINIMUM LENGTH = 32 bytes !!!
ENCRYPTION_KEY=""

# you generate it with `openssl rand -hex 20`
BETTER_AUTH_SECRET=""

# Optional. Omit all three to use the seeded in-memory Azure directory.
# Set all three to connect to Microsoft Graph.
AZURE_TENANT_ID=""
Expand Down
13 changes: 4 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,18 +34,13 @@ Requirements:
```sh
bun dev
```
5. (Optional) Fill the database with sample data: Telegram users, groups and messages, course groups and labels, projects, associations, FAQs, freshman guides, group link reports, audit log entries, grants and staff roles:
5. (Optional) Fill the database with sample data: Telegram users, groups and messages, course groups and labels, projects, associations, FAQs, freshman guides, group link reports, audit log entries and grants:
```sh
bun run seed:db
```
Each table is seeded only while it is empty. New Telegram messages reference retained users and groups, and missing sample FAQ categories are added when the FAQ table is empty. Staff roles, group-admin assignments, and grants are only added for Telegram users created by the current run; group-admin assignments also require groups created by the run.
Each table is seeded only while it is empty. New Telegram messages reference retained users and groups, and missing sample FAQ categories are added when the FAQ table is empty. Grants are only added for Telegram users created by the current run.

`--force` replaces the Telegram activity tables, sample web content, audit logs, and `tg_grants_v2` grants. Existing staff roles and group-admin assignments are preserved.
6. (Optional, for logging into the admin panel locally) Seed a test user with Telegram already linked and the `owner` role:
```sh
bun run seed:user
```
The script sends a sign-in OTP to `test@example.com` and prints a link to a temporary inbox where you can read the code — paste it when prompted. Without this step, logging into admin with `test@example.com` lands on the "Link your Telegram account" onboarding page, since that account has no `telegramId` associated yet. Re-run with `--force` to recreate the test user from scratch.
`--force` replaces the Telegram activity tables, sample web content, audit logs, and grants.

## Authentication

Expand All @@ -56,7 +51,7 @@ Every caller authenticates with a PoliNetwork IdP token ([RFC v3](https://github

Procedures are built with `policy(...)` from `src/trpc.ts`; the bare tRPC procedure is not exported, and `tests/idp-router.test.ts` fails if any procedure lacks a policy. `policy(rules, { tokenOnly: true })` refuses anonymous calls and gives the handler a non-null `ctx.actor`.

Who acted always comes from the token, never from the input: procedures take no actor fields (`createdBy`, `modifiedBy`, `updatedBy`, `adderId`, `interruptedById`, `performerId`, `adminId`). Inputs are plain zod objects, so a key an older client still sends is stripped, not rejected. Content tables record the author in `*_by_sub` columns, and grants go to `tg_grants_v2`. Until Phase 6 a grant counts as active if it is active in either `tg_grants` or `tg_grants_v2`. The bot records moderation actions with `tg.auditLog.record`, which takes an idempotency key and flags `idp_permission` actions the snapshot does not back.
Who acted always comes from the token, never from the input: procedures take no actor fields (`createdBy`, `modifiedBy`, `updatedBy`, `adderId`, `interruptedById`, `performerId`, `adminId`). Inputs are plain zod objects, so a key an older client still sends is stripped, not rejected. Content tables record the author in `*_by_sub` columns; rows written before the IdP migration keep their author's Telegram ID in `legacy_*_by_tg_id`. Grants are in `tg_grants` and record the grantor's IdP subject. People sign in only through the IdP: the backend has no login of its own. The bot records moderation actions with `tg.auditLog.record`, which takes an idempotency key and flags `idp_permission` actions the snapshot does not back.

The bot's socket.io client authenticates with its service token in `auth.token` (scope `backend:tg:events`) and is disconnected when the token expires; a socket without a token is refused. Set `OAUTH_BOT_CLIENT_ID` on the backend to the same registered OAuth client ID used by the bot. This is the actual client ID, not its display name. Sockets are rejected if this setting is absent, the client ID differs, the token is not a service token or the scope is missing.

Expand Down
Loading
Loading