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
6 changes: 6 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,12 @@ locations.

Do not create shared abstractions before there is a real reuse case.

Within a feature, use descriptive role suffixes when they make a file's
responsibility clearer, such as `.routes.ts`, `.service.ts`, `.middleware.ts`,
and `.schema.ts`. Colocate tests as `<name>.<role>.test.ts`. Group related
capabilities into focused subfolders when a feature grows; avoid broad files
such as `auth.service.ts` or empty layers created only to match a template.


## Frontend Standards

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import {
type ExchangeAuthorizationCode,
type OidcFlowState,
validateReturnTo,
} from './google-oidc.js';
import { createSessionMiddleware } from './session.js';
} from './google-oidc.routes.js';
import { createSessionMiddleware } from '../session/session.middleware.js';

const redirectUri = 'http://localhost:3000/auth/google/callback';
const sessionConfiguration = {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/** Starts Google OIDC authorization with protected state, nonce, and PKCE data. */
/** Defines secure Google OIDC login-start and callback routes. */
import { Router } from 'express';
import {
buildAuthorizationUrl,
Expand All @@ -12,8 +12,8 @@ import {
} from 'openid-client';
import { z } from 'zod';

import type { Env } from '../config/env-schema.js';
import type { GoogleUserProfile } from './google-user.js';
import type { Env } from '../../config/env-schema.js';
import type { GoogleUserProfile } from './google-user.service.js';

const GOOGLE_ISSUER = new URL('https://accounts.google.com');
const DEFAULT_RETURN_PATH = '/';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import type { NodePgDatabase } from 'drizzle-orm/node-postgres';
import { describe, expect, it, vi } from 'vitest';

import { provisionGoogleUser } from './google-user.js';
import { provisionGoogleUser } from './google-user.service.js';

function createDatabaseResult(rows: Array<{ id: string }>) {
const returning = vi.fn(() => Promise.resolve(rows));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/** Atomically provisions or updates a user identified by Google's stable subject. */
import type { NodePgDatabase } from 'drizzle-orm/node-postgres';

import { users } from '../db/schema/index.js';
import { users } from '../../db/schema/index.js';

export type GoogleUserProfile = {
avatarUrl?: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import session from 'express-session';
import request from 'supertest';
import { describe, expect, it } from 'vitest';

import { createSessionMiddleware } from './session.js';
import { createSessionMiddleware } from './session.middleware.js';

const sessionConfiguration = {
SESSION_SECRET: 'test-session-secret-at-least-32-characters',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import connectPgSimple from 'connect-pg-simple';
import session, { type Store } from 'express-session';
import type { Pool } from 'pg';

import type { Env } from '../config/env-schema.js';
import type { Env } from '../../config/env-schema.js';

declare module 'express-session' {
interface SessionData {
Expand Down
6 changes: 3 additions & 3 deletions apps/api/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import { createApp } from './app.js';
import {
createGoogleOidcRouter,
discoverGoogleOidc,
} from './auth/google-oidc.js';
import { provisionGoogleUser } from './auth/google-user.js';
import { createPostgresSession } from './auth/session.js';
} from './auth/google/google-oidc.routes.js';
import { provisionGoogleUser } from './auth/google/google-user.service.js';
import { createPostgresSession } from './auth/session/session.middleware.js';
import { env } from './config/env.js';
import { createDatabase } from './db/client.js';

Expand Down
11 changes: 11 additions & 0 deletions docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,11 @@ A conceptual feature organization might be:
apps/api/src/
features/
auth/
google/
google-oidc.routes.ts
google-user.service.ts
session/
session.middleware.ts
exercises/
routines/
workouts/
Expand All @@ -437,6 +442,12 @@ Each backend feature may contain the pieces needed by that feature, such as:

Do not force every feature to contain every layer.

Use descriptive role suffixes such as `.routes.ts`, `.service.ts`,
`.middleware.ts`, and `.schema.ts` where they clarify responsibility. Colocate
tests as `<name>.<role>.test.ts`. Prefer focused capability names over broad
files such as `auth.service.ts`, and introduce controllers or other layers only
when their separation provides real value.


# 17. Backend Separation of Concerns

Expand Down