backend
GitHub用于 InsForge 后端代码维护,涵盖路由、服务、认证、数据库及测试。规范了分层架构、PostgreSQL 交互及迁移脚本编写规则。
Trigger Scenarios
Install
npx skills add InsForge/InsForge --skill backend -g -y
SKILL.md
Frontmatter
{
"name": "backend",
"description": "Use this skill when contributing to InsForge's backend package. This is for maintainers editing backend routes, services, providers, auth, database logic (including RLS-enforced surfaces like storage and realtime), schedules, or backend tests in the InsForge monorepo."
}
InsForge Dev Backend
Use this skill for backend/ work in the InsForge repository.
Scope
backend/src/api/**backend/src/services/**backend/src/providers/**backend/src/infra/**backend/tests/**
Working Rules
-
Keep the route -> service -> provider/infra split intact.
- Routes handle auth, parsing, validation, and delegation.
- Services own business logic and orchestration.
- Providers and infra wrap external systems or lower-level integrations.
- Service layer code should be the only layer that interacts with the core PostgreSQL database.
- Do not put direct database access in routes.
- Do not bypass services when reading from or writing to Postgres.
-
Follow backend conventions.
- Use ESM-style
.jsimport specifiers in TypeScript source. - InsForge's core database is PostgreSQL.
- InsForge currently runs as a single-instance server, so be careful about introducing logic that assumes distributed coordination, cross-instance locking, or background worker separation.
- Reuse shared schemas from
@insforge/shared-schemaswhen contracts cross packages. - Use
safeParseplusAppErrorfor invalid input. - Return successful results through
successResponse. - Preserve existing auth middleware patterns such as
verifyAdmin,verifyUser, andverifyApiKey. - Never use the TypeScript
anytype. Prefer precise interfaces, schema-derived types,unknown, or constrained generics. - A new environment variable must be documented in the repository's single
.env.example. Every compose file reads that one file, so a variable missing from it is one self-hosters cannot discover — the S3 storage settings went undocumented that way for months. deploy/coolify/docker-compose.ymlanddeploy/dokploy/docker-compose.ymlcarry identical service definitions apart from two lines:INSFORGE_DEPLOYMENT_METHOD, which telemetry reads to tell the two platforms apart, and the buildcontext, which differs because Coolify builds with--project-directory <repo root>and Dokploy does not. Their header comments are per-platform by design. Change both, or one platform silently misses whatever you added.- For schema changes, write a new migration file instead of editing database structure manually.
- Put schema changes under
backend/src/infra/database/migrations/.
- Use ESM-style
-
Write idempotent migrations. Every SQL migration must be safe to re-run.
- Use
CREATE TABLE IF NOT EXISTS,CREATE INDEX IF NOT EXISTS,ADD COLUMN IF NOT EXISTS. - Never use bare
ALTER TABLE ... RENAME TO— it fails if the target name already exists. Wrap renames in aDOblock that checksinformation_schema.tablesfor both source and target. - Always
DROP TRIGGER IF EXISTSbeforeCREATE TRIGGER. - Guard data migrations and
DROP COLUMNbehindinformation_schema.columnschecks when the column may already be gone. - Use
ON CONFLICTorWHERE NOT EXISTSfor seedINSERTstatements.
- Use
-
Preserve existing behavior around mutation flows.
- Keep audit logging when surrounding routes already log state changes.
- Keep error handling flowing through shared middleware.
- Do not introduce a new response envelope unless the existing feature already uses one.
- For critical flows with multiple dependent database writes, use an explicit transactional process so the whole operation succeeds or fails together.
- Be especially careful with transactions around auth, secrets, billing-like usage updates, schema changes, and any flow that would leave the system inconsistent if partially applied.
-
Use Postgres Row Level Security, not app-side filters, for tables accessed via authenticated end-user routes (anything where
req.userreaches the service layer). RLS-enforced services such as storage, realtime, and payments should usewithUserContext. Tables accessed only by admin or service-internal paths (audit logs, billing aggregations) don't need RLS. Do not writeWHERE user_id = $1filters in services; let RLS evaluateauth.jwt() ->> 'sub'against the row.- Plumb identity through
withUserContext(pool, ctx, fn, settings?)fromservices/database/user-context.service.ts. It opens a transaction, setsSET LOCAL ROLEplus the canonicalrequest.jwt.claimsJSON GUC viaset_config, applies optional transaction-local settings such asrealtime.channel_name, runsfn, commits on success or rolls back on error, and resets role infinallyso policies see the calling user viaauth.jwt() ->> 'sub'. - Keep
UserContextuser-only and defined inapi/middlewares/auth.ts:{ id, role, email? }(idis always present at the API level). API keys and admin bypass flags do not belong insideUserContext. - Routes that issue out-of-band URLs (S3 presigned redirects, signed download links, anything the client redeems against a service that won't re-evaluate RLS) must do an explicit RLS-scoped existence check before handing the URL out — RLS does not fire when the client redeems the URL directly. See
StorageService.objectIsVisibleas the template. - Migrations that enable RLS on an existing populated table must auto-install a sensible default policy set so the upgrade does not silently break existing rows. See migration 036's
IF EXISTS (SELECT 1 FROM <table>) THEN <create policies> END IFpattern. - When adding a new RLS-enforced table: enable RLS,
GRANTtable-level CRUD toauthenticated, and write per-operation policies (SELECT, INSERT, UPDATE, DELETE). Public-bucket-style anonymous bypasses live at the route layer before calling the RLS helper, not in policies. - Normal raw SQL and custom migrations execute as
project_admin. It has service-key row visibility, but PostgreSQL grants and ownership still limit object access and DDL.
- Plumb identity through
-
Always write unit tests for new code.
- Every new feature, migration, service, or bug fix should have accompanying unit tests.
- For migrations, write tests that validate SQL structure and idempotency guards (see
tests/unit/redirect-url-whitelist-migration.test.tsfor the pattern). - For services, test business logic and error cases.
- For RLS-gated services, mock the pool/client and pin the SQL sequence (see
tests/unit/user-context.service.test.tsandtests/unit/storage-object-is-visible.test.ts). - Run the full test suite before submitting work:
cd backend && npm test.
Validation
cd backend && npm testcd backend && npm run build
For contract changes, also validate packages/shared-schemas/ and any affected dashboard consumers.
Version History
- 4bf10d7 Current 2026-08-20 09:26


