AI-Assisted CRUD Feature Under Review
Before you start
You need: all of Articles 01–07, and an API project to extend.
Time: 8–12 hours. The review record is the deliverable, not the feature.
Goal
Build one complete feature using AI, in increments you verify, and produce a review record showing you caught what generated code gets wrong.
Assignment
Build the Staff management feature of the School Management System — list, create, update, deactivate — using AI throughout, then review every line against the checklists.
The deliverable is the review record, not the feature. Anyone can generate CRUD. The exercise is showing what you checked, what you found, and what you rejected.
Staff { Id, PublicId(Guid), SchoolId, UserId, Name, EmployeeCode,
Designation(enum), Department, Salary, JoiningDate, IsActive }
StaffDesignation: Clerk, Librarian, LabAssistant, Accountant, Peon, Security
Rules the feature must satisfy — none of which a model can infer:
SchoolIdfrom the auth claim, never a request parameter, filtered in every queryEmployeeCodeunique per school:UNIQUE (SchoolId, EmployeeCode)Salaryisdecimal/DECIMAL(18,2)— never float- Deactivate sets
IsActive = 0; it never deletes - Every read excludes inactive staff unless explicitly requested
- Only Admin and Principal may create, update or deactivate
Salaryis visible only to Admin and Principal, never to other roles
That last rule is the interesting one. A generated DTO will include Salary because it is on the entity, and nothing will fail.
Part 1: Set up the context
Write a CLAUDE.md (or .cursorrules) before generating anything:
# School Portal — AI context
## Stack
ASP.NET Core 9 Web API, Dapper, SQL Server 2022, xUnit.
## Non-negotiable rules
- SchoolId comes from the auth claim, never a request parameter.
Every query filters by SchoolId.
- Soft delete / deactivation, never hard delete. Reads exclude inactive rows.
- Money: decimal in C#, DECIMAL(18,2) in SQL. Never float or double.
- Uniqueness is composite: (SchoolId, EmployeeCode).
- Parameterised SQL only. Never string concatenation.
- Salary is exposed only to Admin and Principal.
## Style
Full braces. No expression-bodied members. Explicit types over var.
Async methods end in Async. Repositories return entities; controllers return DTOs.
Record which rules you had to state explicitly, and later, which ones were violated anyway.
Part 2: Build in increments
Six steps. Verify each before starting the next, and commit each separately.
| Step | Verify by |
|---|---|
| 1. SQL schema and the composite unique constraint | Insert a duplicate code for a second school — must succeed; same school — must fail |
2. StaffRepository — list, get, insert, update, deactivate | Run each against seed data |
3. StaffService — business rules | Unit tests for each rule |
4. StaffController — endpoints, authorisation, DTOs | Postman, including the negative cases |
| 5. Frontend list and form | Network response versus rendering |
| 6. Tests | Each fails without its fix |
Commit before every generation. git status clean, generate, git diff --stat, git diff, review, commit.
Record for each step: the prompt, whether the first output was acceptable, what you corrected, and how many iterations it took.
Part 3: The review record
For every generated file, work the checklists and record what you find.
File: src/Data/StaffRepository.cs
Generated in: step 2, iteration 2
Security
Parameterised SQL: pass / FAIL — details
No hardcoded connection string: pass / FAIL
No secrets: pass / FAIL
Multi-tenant
SchoolId from the claim: pass / FAIL
SchoolId in every WHERE: pass / FAIL — which query
Composite uniqueness: pass / FAIL
Cache keys include SchoolId: pass / n-a
Correctness
Inactive rows excluded: pass / FAIL
Null handling (empty result, SUM): pass / FAIL
First/FirstOrDefault with ordering: pass / FAIL
Join row counts checked: pass / n-a
Every command inside a transaction
receives the transaction: pass / FAIL / n-a
Types
Salary is decimal: pass / FAIL
DECIMAL(18,2) in SQL: pass / FAIL
DateTime.UtcNow, not Now: pass / FAIL
Async and resources
Every task awaited: pass / FAIL
No .Result or .Wait(): pass / FAIL
Connections in using blocks: pass / FAIL
Scope
Anything I did not ask for: list it
Anything invented (methods, config): list it
Understanding
Lines I could not explain: list them, then resolve each
Any "FAIL" needs the corrected code and a note on whether an error would ever have surfaced. That column is the most valuable part of the record.
Part 4: The salary test
The rule most likely to be violated silently: Salary must not reach a Teacher or Staff role.
// Likely generated — leaks Salary to every role
return Ok(await _staffRepository.GetBySchoolAsync(schoolId));
// Correct
if (User.IsInRole("Admin") || User.IsInRole("Principal"))
{
return Ok(staff.Select(StaffDetailDto.From));
}
return Ok(staff.Select(StaffSummaryDto.From)); // no Salary
Test it as a breach, not as a unit test. Sign in as a Teacher, call the endpoint, and read the raw JSON in the Network panel. Salary must not be present — not hidden in the UI, absent from the response.
Record the response body, before and after the fix.
Part 5: Deliberate failure cases
Generate each of these and record what came back. Do not correct the prompt first — the point is to observe the default.
| Prompt omits | Check |
|---|---|
| The tenant rule | Does the query filter SchoolId? |
| The deactivate rule | Does it generate DELETE? |
| The money rule | Is Salary a decimal? |
| The DTO rule | Does the response expose Salary? |
| The uniqueness rule | Is the constraint on EmployeeCode alone? |
Then add each rule to the prompt and confirm the output changes.
This is the measurement that makes the rest of the track concrete: you learn the specific rate at which your assistant needs telling.
Part 6: Debug a planted defect
Have a partner plant one defect in your finished feature — or plant one, wait a day, and shuffle.
Debug it using the track 17 method: reproduce, trace boundaries, hypothesis, test.
Then ask an AI about it twice: once with no evidence, once with the full evidence set and what you have ruled out. Record both answers and which was useful.
Submission template
Context file
Rules stated:
Rules violated anyway, and how often:
Increments
Step | Prompt summary | First output OK? | Corrections | Iterations
1..6
Review records
One per generated file, per the Part 3 template.
Totals:
Security findings:
Multi-tenant findings:
Correctness findings:
Type findings:
Unrequested additions removed:
Invented APIs:
Findings that would never have produced an error:
Salary test
Response body as a Teacher, before the fix:
After the fix:
Deliberate failure cases
Rule omitted | What was generated | With the rule stated
Planted defect
Symptom:
Boundary trace:
Cause and fix:
AI answer with no evidence:
AI answer with evidence:
Which helped, and why:
Git record
git log --oneline (paste):
Confirmation that every generation was preceded by a clean status:
Any generation you reverted, and why:
Ownership
Can you explain every line? yes / no — which lines
Could you debug this at 2am? yes / no
Would you defend it in review? yes / no
Do you know what happens on bad input? yes / no
Verification
The feature works. List, create, update and deactivate all function, with the negative cases returning 403 rather than succeeding.
Every rule is enforced server-side. Test each from Postman, which bypasses every frontend control.
The salary rule is proved by a response body, not by a screenshot of a hidden column.
SchoolId is proved by a cross-tenant request. Sign in as School 1, request School 2's staff, get 403 or an empty result — never data.
Every commit was preceded by a clean working directory. git log shows one verified change per commit, with no commit mixing generated and hand-written work.
Every test fails without its fix. Comment out the implementation, run, watch it fail, restore.
The review record has findings. A record with no findings across six generated files means the review was not performed — the deliberate failure cases in Part 5 will show you the true rate.
No secret and no real personal data appears anywhere, in the code or in the prompts you recorded.
Self-assessment
Your submission is complete when the feature works, the review record shows real findings, and you can answer the ownership questions with four yeses.
Five specific tests:
- How many findings produced no error message? Those are the ones this whole track exists for — the tenant filter, the salary leak, the money type, the missing deactivation.
- Did stating a rule in the context file actually prevent its violation? Part 5 measures it. Whatever rate you observe is the rate you must catch in review, permanently.
- Could you have found the planted defect without AI? If not, practise track 17's method, not this one's.
- Which parts did you write by hand, and why? Nothing on this list should be entirely generated. If everything was, you did not hit the "third attempt, write it yourself" threshold, or you accepted something you should not have.
- Can you explain every line? Not the general shape — line by line. Any line you cannot explain is a line to rewrite before this ships.
Track completion criteria
You can use AI tools productively while keeping the understanding, verification and ownership that make you employable.
Specifically, you can:
- Use AI to learn rather than to avoid learning
- Ask for critique of your attempt rather than an answer
- Recognise the dependency trap in your own work
- Give a model the context it cannot infer — stack, entities, conventions, business rules
- Show a convention by example rather than describing it
- Iterate on an answer instead of restarting
- Maintain a project instruction file and keep it current
- Work in increments small enough to verify
- Review generated code against security, correctness, multi-tenant and type checklists
- Catch the failures that produce no error: tenant filter, absent-before-pass, money types, silent joins, unawaited tasks
- Give an AI the evidence a bug needs, and test its suggestions
- Refactor without changing behaviour, in separate commits
- Specify test cases from the requirement, not the implementation
- Decide where fast AI building is appropriate and where it is not
- Keep credentials and regulated data out of prompts
- Use commit boundaries and diff review so every generation is reversible
- Take responsibility for everything you commit
You have completed the NexCoding curriculum. The syllabus recommends reinforcing it with Track 16 — Git & Source Control or Track 01 — Microsoft .NET Full Stack Guided Path. Return to the 18-track curriculum for the full picture.