Imported from YourTongji/YourTJ-Hub (
AGENTS.md). Install upstream withnpx skills add YourTongji/YourTJ-Hub. Copyright stays with the author.
AGENTS.md — yourtj-hub
Operating guide for anyone (human or AI agent) changing this repository.
Before changing anything, read this file, docs/README.md,
docs/development/README.md, and the product/architecture/operations
documents directly affected by the request. Use the repository $yourtj-development skill for
implementation, testing, review, CI, or PR work.
1. What this is
yourtj-hub is the monorepo for the Tongji university campus forum platform (brand: yourtj, distinct from
the archived YourTJ-Platform). The forum is the core product — a direct modification of the upstream
GooseForum, keeping the single-binary deployment. Unified auth (built-in OIDC Provider), search (Meilisearch), and
cross-platform points (credit, Planned) are shared infrastructure subdomains. Database, search, and structure may all
be changed, but the "Go + Vue in one binary, frontend go:embed into the binary" deployment shape is kept.
- Forum: Go 1.26 + Gin + Vue 3 + Tailwind, at
apps/gooseforum(fork of upstream; module pathgithub.com/YourTongji/YourTJ-Hub/apps/gooseforum, diverged from upstream'sgithub.com/leancodebox/GooseForum). - Backend layers (upstream structure):
app/bundles(utilities) →app/models(GORM models) →app/service(business) →app/http/controllers/{api,forum}(JSON API + GoHTML three-mode rendering). - Frontend:
apps/gooseforum/resource(Vue 3 + Vite, site/admin dual entry), built outputresource/static/distgo:embed; GoHTML templates inresource/templateskeep server-side rendering (three-mode). - Database: PostgreSQL is the default deployment database (
deploy/config.toml.example[db.default] connection = "postgres"); SQLite stays the local development/test default (apps/gooseforum/config.toml, in-memory tests); the file db ([db.file]) is fixed SQLite. MySQL is not supported. - Search: Meilisearch (
config.toml [meilisearch], optional); aggregate search (topics/users/ categories, pinyin/initials) landed (issue #22); event-driven index sync, rebuildable projection. - Mobile: Flutter (
apps/mobile, melos workspace, Riverpod, Partial). - Auth: GitHub OAuth (goth) + built-in OIDC Provider (
/api/oauth, authorization code + PKCE S256, RS256 id_token, opaque access tokens, numericsub= users.id); TOTP 2FA and session management (jti+user_sessions) in place. - Contract: Partial —
packages/api-contract/openapi.yamlis the controlled contract center for password login, login public-key retrieval, TOTP login verification and account management, logout, mobile OIDC exchange, session management (list/revoke/revoke-all), topic writing, forum core interactions (post create/update/delete/window/revisions, topic status/delete/like/bookmark/watch, post like/bookmark, follow-user, report), user account and identity (captcha, user-card, profile/email/username/avatar/badge settings, upload-avatar, change-password, OAuth bindings/unbind), notifications/unread/chat, forum moderation workbench, the admin console (/api/admin/*: user/role/category/moderator management, topic/post moderation, agent administration, operation records, traffic overview, page settings, site settings, data import/export), account registration/password recovery (/api/register,/api/forgot-password,/api/reset-password), the six-operation Agent forum API, course catalog reads + review write/moderation, the Wiki domain (public tree/namespaces/home + admin read-only tree + sync/status|sync|sync/runs + sync/webhook-secret + asset CDN + webhook; the legacy in-forum write/revision/rollback/diff/editor and namespace-CRUD endpoints were retired with the GitHub-SSoT model), and the PK scheduler (14 ops: courses-by-major/optional-types/courses-by-nature/course-details/course-search/courses-by-time/ latest-update/course-info-sync/course-review-brief), the user content lifecycle (my-content/deleted-content lists, content-restore/batch-delete/ purge/event, account-close), aggregate search (/api/forum/search) and public site statistics, the sticker library (GET /api/forum/stickerspublic enabled list +/api/admin/stickers/sticker-save/sticker-delete/sticker-importadmin CRUD and zip pack import; token[:sticker:name:]expanded server-side at render for posts/replies and client-side in chat bubbles (web segmented renderer) and mobile (markdown pre-expansion + inline image spans) via the public list API, MADR 0030), with lint/bundle, generated TypeScript types, fixtures, and route-level HTTP tests; paths are split per domain underpaths/. Route coverage (issue #277) is complete:route-coverage.jsonknownUncovered is empty — every non-excluded/apiroute has a contract operation; new routes must be added to the contract or the exclusion list. - Points: forum-local ledger mechanics are
Current, durable reward delivery isPartial; cross-platform credit settlement isPlanned. Seedocs/product/credit-and-escrow.md.
2. Repository layout & boundary rules
apps/
gooseforum/ The forum itself (upstream fork; module path github.com/YourTongji/YourTJ-Hub/apps/gooseforum)
main.go Entry point (cobra: serve / migrate / seed-demo / seed-stickers / mock-topics / mock-posts / rebuild-search-index ...)
config.toml Runtime config (gitignored; bring your own locally)
app/ Go backend (bundles/console/datastruct/http/migration/models/service)
resource/ Vue 3 frontend + gohtml templates + @gooseforum/client package
docs/ Fork-owned docs (maintained in this monorepo, not reference-only)
status/ Independent Vue status site + Netlify Functions/Blobs (status.yourtj.de)
mobile/ Flutter melos workspace (core/auth/ui_kit/forum_app)
packages/
api-contract/ openapi.yaml + gen scripts + fixtures + contract tests (Partial)
services/
search/ Meilisearch deployment config
credit/ Cross-platform credit settlement (Planned placeholder)
deploy/ Per-environment compose + env.example
docs/ Docs center (product/architecture/development/operations)
Boundary rules
apps/gooseforumis the only place the forum is implemented; business logic inservice, data access inmodels/repository layer, HTTP inhttp/controllers.- Cross-domain access goes through the owner's public API; no foreign SQL against other domains' tables.
- Frontend output only via
resource/static/dist(go:embed); the backend proxies/assetsto Vite :3010 in dev, single binary in production. services/holds deployment configs only, not third-party source (Meilisearch/credit are off-the-shelf components).- Upstream sync:
git mergeupstream main; resolve conflicts with "our changes win" and record it. After merging, rewrite upstream'sgithub.com/leancodebox/GooseForumimport prefix togithub.com/YourTongji/YourTJ-Hub/apps/gooseforum(upstream files keep the old prefix), then rungo mod tidy.
3. Hard constraints
- Forum deployment shape is a single binary (go:embed webdist/static-dist); no nginx/CDN split.
The independent public status app (
apps/status) deploys its Vue assets and Functions to Netlify, with no runtime dependency on the forum. Seedocs/operations/status-netlify.md. - User IDs must be numeric (uint64) — credit's
GetID()only accepts numeric sub; the built-in OIDC Provider always issuessub= users.id (uint64 decimal string). - The forum
userstable is the identity source; the forum JWT is a session credential, not identity truth, and is never issued to external OIDC clients. - For OpenAPI-covered operations, contract changes ship in the same PR: backend behavior/structs →
openapi.yaml→ generated TypeScript output → fixture contract tests. Until the pipeline fully covers an operation, contract changes must also update the mobile Dart mirrors inapps/mobile/packages/core/lib/src/gen/(same PR) and web TS types (resource/packages/client/src/contracts/) in the same commit. Dart generation remains Planned. Route coverage is gated: every route fromRegisterByGin(snapshotpackages/api-contract/fixtures/routes-snapshot.json, regenerate withYOURTJ_UPDATE_ROUTES_SNAPSHOT=1 go test ./app/http/routes/ -run TestRoutesSnapshot) must be an OpenAPI operation or listed inpackages/api-contract/route-coverage.json, and the generatedpackages/api-contract/coverage-matrix.mdmust be committed —pnpm run checkand CI fail otherwise. - Design-token changes ship in the same PR: changing
resource/src/styles/tokens.cssrequires updatingapps/mobile/packages/ui_kit/lib/src/theme/tokens.jsonin the same commit. - Web
serverMessageschanges ship in the same PR: changingserver/serverMessageskeys inresource/src/locales/{zh,en,ja,de}.tsrequires regenerating the mobile mirror catalogapps/mobile/packages/forum_app/lib/src/server_message_catalog.dart(node apps/mobile/tools/generate_server_messages.mjs) in the same commit. The gate ispnpm checkinapps/gooseforum/resource: four-locale key consistency, statict()registration, and mirror-catalog freshness. - Docs use the four implementation status words (
Current/Partial/Planned/Decision needed), see docs/README.md. - Docs describe only the currently supported model — no timeline or milestones (see docs/development/documentation.md).
- Any new feature PR must include documentation changes: user-visible features update the docs center and status words; purely internal changes at least update the relevant README or code comments (see docs/development/documentation.md).
- config.toml contains signingKey — never commit it (gitignored).
- Research files goto research/, and should not be included in git.
4. Verification
-
Run only the checks relevant to the change locally; CI owns the full repository-wide gate matrix. Before push, lefthook pre-push runs
go vet ./...+golangci-lint run(incremental againstorigin/dev, full fallback) +pnpm typecheck+ the web i18n gatepnpm check(seemake hooks). -
Bug fixes start red: write the smallest failing test first, run it to confirm the failure, then implement and turn it green. Mechanical changes (rename, formatting, dependency bump, docs-only) are exempt; the regression test stays.
-
TODO markers use three tiers (
FIXME/TODO/XXX), see docs/development/coding-conventions.md. -
Test layout follows the per-language convention (Go
*_test.goco-located, frontendresource/test/, Fluttertest/, contract fixtures underpackages/api-contract/fixtures/), see docs/development/testing.md#test-layout. -
Backend:
cd apps/gooseforum && go vet ./... && go test ./...(useGOPROXY=https://goproxy.cn,directif module fetch times out). Any model/migration change must also pass the PostgreSQL migration tests:YOURTJ_TEST_PG_URL="host=127.0.0.1 port=5432 user=postgres password=postgres dbname=postgres sslmode=disable" go test ./app/migration/ -run 'TestSchema' -v(bothTestSchemaMigratesOnPostgreSQLandTestSchemaUpgradeCreatesNewTablesOnPostgreSQLinapp/migration/migration_pg_test.go; spin uppostgres:16-alpinelocally — CI runs the same command inci-backend-pg). MySQL-only type tags (bigint unsigned/datetime/tinyint) break PG and are forbidden in models (MySQL itself is not supported). -
Web:
cd apps/gooseforum/resource && pnpm typecheck && pnpm test && pnpm check && pnpm build(pnpm checkis the i18n gate; output into resource/static/dist) -
Full build:
make build(resource → go build single binarybin/yourtj-hub) -
Smoke: run
./bin/yourtj-hub servethen curl the homepage/API (port from config.toml, default 5234) -
Report the commands actually run and their results; a local subset is not CI passing.
-
Governance gates:
node scripts/run-gates.mjs(doc links / placeholders / manifest / decisions MADR / postmortem format; seeded by repo-seed, owned by.repo-seed/manifest.json). Fast — run early.
5. Git & PR discipline
devis the main development line: createfeat/<topic>/fix/<topic>/docs/<topic>fromorigin/dev, open PRs againstdev; CI builds and auto-deploysdevto the test instance.mainis the production site: changes reach it through PR + CI.Release / mainmerges the release PR, publishes a server tag and dispatches production deployment on that tag (seedocs/operations/deployment.md). Never develop directly onmainordev.- The dev instance syncs a consistent snapshot of the main database on each deploy (see
docs/operations/deployment.md), so DB migrations are rehearsed on dev before reaching main. - Stage only files this task owns; leave unrelated dirty/untracked files alone.
- Commit/push/open a PR only when the user explicitly asks.
- Never push to protected branches; releases go through PR + CI.
- Commit messages use concise conventional types (
feat:/fix:/docs:/refactor:/chore:).
6. Reference
- Docs center (fact-source table + status words)
- Development entry
- Repository skills:
$yourtj-development,$yourtj-pre-push-checks,$yourtj-simplifications,$yourtj-doc-standards,$yourtj-code-review(see.agents/skills/); repo-seed governance skillsrepo-review,repo-decisions,repo-governance(upgrade channel:.repo-seed/update-strategy.md) - Decision records: MADR log in docs/decisions/ (gate
node scripts/verify-decisions.mjs); the legacy host-note ADR archive is frozen (append-only, no new records) - Upstream: GooseForum (apps/gooseforum, the fork itself); YourTJ-Platform (local, same-brand archived repo)
