Skip to content

Latest commit

 

History

History
139 lines (99 loc) · 9.7 KB

README.md

File metadata and controls

139 lines (99 loc) · 9.7 KB

ProCoderJii account and progress API

ASP.NET Core 10 provides Google sign-in, server-managed cookie sessions, and durable learner progress. The Next.js app forwards /api/platform/* to this service through its server-only BFF. Anonymous browser practice stays available when the backend or Google credentials are not configured.

Run locally

Install a supported .NET 10 SDK and keep its runtime on the latest servicing patch. From the repository root:

dotnet restore backend/ProCoderJi.slnx --locked-mode
dotnet run --project backend/src/ProCoderJi.Api

The development profile listens on http://localhost:5100. Set DOTNET_API_URL=http://localhost:5100 in the frontend's .env.local and run Next.js separately. This URL is server configuration and must never use a NEXT_PUBLIC_ prefix.

SQLite is the default development provider. The API creates and migrates backend/src/ProCoderJi.Api/Data/procoderji.db automatically in Development. Users, progress, and ASP.NET Data Protection keys survive process restarts in that database. Generated databases and build output are ignored by Git.

Google sign-in

Create a Google OAuth Web application client and register this exact local authorized redirect URI:

http://localhost:3000/api/platform/signin-google

The callback belongs to the frontend origin, which forwards it to ASP.NET Core. The backend's PublicOrigin configuration defaults to http://localhost:3000 in the checked-in development settings. It determines OAuth callback URLs, allowed return paths, mutation-origin checks, and cookie security. Set it to the actual HTTPS frontend origin in production.

Keep credentials in .NET user secrets locally:

dotnet user-secrets set --project backend/src/ProCoderJi.Api "Authentication:Google:ClientId" "YOUR_CLIENT_ID"
dotnet user-secrets set --project backend/src/ProCoderJi.Api "Authentication:Google:ClientSecret" "YOUR_CLIENT_SECRET"

Deployment environments can instead supply Authentication__Google__ClientId and Authentication__Google__ClientSecret. These are backend secrets; never commit them or expose them through frontend environment variables. Without both values, the session endpoint reports configured: false and the Google challenge returns 503 while guest practice remains available.

Users are linked by Google's stable provider subject, never by matching email addresses. The app stores its own internal UUID plus the provider subject and current email/display name. Cookies contain the internal account identity; provider access/refresh tokens are not retained. Sessions are HttpOnly, SameSite=Lax, and Secure on HTTPS deployments.

API contract

Endpoint Behavior
GET /api/platform/auth/session Returns { configured, user, csrfToken } and issues the antiforgery cookie.
GET /api/platform/auth/google?returnTo=/learn Begins Google OAuth; return URLs stay under approved learning/account paths on PublicOrigin.
/api/platform/signin-google OAuth middleware callback; requires valid state/correlation.
POST /api/platform/auth/logout Clears the session cookie; requires current antiforgery token and same-origin request.
GET /api/platform/progress Returns { attempts, generation } for the authenticated account.
POST /api/platform/progress Accepts { attempts, generation }; validates questions/answers and inserts immutable attempts idempotently.
DELETE /api/platform/progress Deletes the account's attempts and rotates its generation atomically; returns { generation }.

Progress requests include x-account-id matching the signed-in user to reject account-switch races. Mutations also require Origin matching PublicOrigin and X-CSRF-Token obtained from the current session response. A token issued before sign-in/account change must be refreshed. Private responses use private, no-store; the BFF preserves cookie and redirect headers.

Attempts store raw question IDs and selected answers, not trusted scores. The backend validates against shared/practice/questions.json, which is copied into the API output as Data/questions.json. Grading remains reproducible from the canonical bank. This introductory practice is not a proctored or hiring assessment.

Serializable transactions and a state concurrency token serialize sync/reset races. A reset rotates the generation, so old devices cannot silently restore deleted cloud history. Attempts are keyed by account plus session UUID, and the newest 100 are retained per account. Requests are limited to 100 attempts and 256 KiB.

Choose a database

Neon PostgreSQL is the selected hosted database. Follow Neon setup for the runtime and migration connections. The other providers remain available for contributors.

Choose one provider per deployment. These are operator settings; students use the same account and progress API with every provider. SQLite remains the default for development without Docker.

Database__Provider Storage Required configuration
Sqlite Local SQLite file through EF Core Optional ConnectionStrings__Platform; defaults to Data/procoderji.db.
Postgres PostgreSQL through EF Core/Npgsql ConnectionStrings__Platform with a PostgreSQL connection string.
SqlServer Microsoft SQL Server through EF Core ConnectionStrings__Platform with a SQL Server connection string.
MongoDb MongoDB through the official .NET driver MongoDB URI in ConnectionStrings__Platform, plus Database__Name.

The API, migrations, and selected database can run together with Docker Compose, in separate containers with persistent database volumes. Follow Container setup. Vercel container deployments need an external durable database; Compose volumes are for a Docker host. Changing providers does not copy existing data or sessions between databases.

Example backend-only PostgreSQL configuration:

Database__Provider=Postgres
ConnectionStrings__Platform=Host=YOUR_HOST;Database=YOUR_DATABASE;Username=YOUR_USER;Password=YOUR_PASSWORD
PublicOrigin=https://YOUR_FRONTEND_ORIGIN

For SQL Server, use Database__Provider=SqlServer and a connection string such as Server=YOUR_HOST;Database=procoderji;User Id=YOUR_USER;Password=YOUR_PASSWORD;Encrypt=True;TrustServerCertificate=False. For MongoDB, use Database__Provider=MongoDb, Database__Name=procoderji, and ConnectionStrings__Platform=mongodb+srv://YOUR_USER:YOUR_PASSWORD@YOUR_HOST/. Keep actual credentials in user-secrets or the hosting secret store.

Provision and deploy

Run migrations deliberately before starting production replicas:

dotnet run --project backend/src/ProCoderJi.Api --no-launch-profile -- --migrate

This command uses the current environment's database/provider settings and exits after provisioning. It applies EF migrations for relational databases and creates MongoDB's unique Google-subject index for MongoDB. Development and Testing provision automatically; production does so only for --migrate or explicit Database__MigrateOnStartup=true. Back up the database before schema changes. Shared relational migrations contain provider-specific SQL where needed; keep both the default and SQL Server model snapshots current and run the provider checks.

Data Protection keys are stored in the selected application database with a stable application name, so replicas using the same database can decrypt sessions. Relational storage uses EF Core; MongoDB uses a key collection and an XML repository. Protect database access, backups, and key material at rest, and isolate key rings between deployments. Restrict direct network access to the backend and use the frontend BFF as the public entry point. Configure infrastructure rate limits, HTTPS, operational monitoring, and backups before public account launch.

MongoDB stores each account's progress generation, revision and 100 retained attempts in one document. Conditional atomic writes preserve reset and immutable-attempt behavior without a replica set or multi-document transactions. See ADR 0003.

Razorpay or Paytm integration is planned for a later billing slice. No payment, subscription activation, or live checkout is implemented in this API yet.

Tests

dotnet test backend/ProCoderJi.slnx --no-restore

The default suite creates isolated SQLite databases and uses test-only authentication registered by WebApplicationFactory in the test assembly. The API has no test-header login path. Tests cover anonymous behavior, Google challenge URL construction, CSRF/origin checks, account isolation, immutable sync, generation resets, stale requests, question validation, and retention.

To run the same API contract tests against a disposable server, set exactly one of PROCODERJI_TEST_POSTGRES, PROCODERJI_TEST_SQLSERVER, or PROCODERJI_TEST_MONGODB to its administrative test connection string. Each factory creates and drops only its randomly named test schema/database. The MongoDB setting also enables its persistence and Data Protection integration tests, which otherwise report skipped. Never use a production database for these tests. The backend-container workflow exercises all three servers and the packaged API. A real Google login still needs operator-provided credentials and a live callback check.

References