Chapter 14 Full Lifecycle Walkthrough: Delivering a Project from Scratch with Effective Constraints
2026.08.10Theory is a map; practice is a voyage. No matter how precise the map, it cannot replace the experience of sailing through real storms. In this chapter, we will jointly "pilot" the great ship of AI through a complete project voyage.
We will start with an empty folder and strictly follow all the constraint principles established in this book, step by step, to build a fully functional, quality-assured application.
In this process, you will see:
- How architectural constraints, like the "keel," establish stability and direction from the very beginning of the project.
- How process constraints, like "navigation charts" and "operating procedures," guide us away from the hidden reefs of thinking.
- How environmental constraints, like "radar" and "sonar," help us perceive and respond to invisible external risks.
- How quality constraints, like a "hull integrity monitoring system," constantly guard our voyage safety, preventing "accumulated fatigue from leading to failure."
Ready? Hoist the sails. Set course.
14.1 Background: A Cross-Platform, Offline, High-Security Universal Case Study
To make this exercise sufficiently universal and challenging, I have carefully designed a case study that covers a variety of common technical challenges: a secure, cross-platform, offline-capable note-taking application -- "Guardian Notes."
Core Requirements (from the "Product Manager's" original requirements):
"We want to build a note-taking app where users can write private diaries and memos. Our biggest selling points are 'security' and 'accessible everywhere.' Specifically:
- High-security objective: Note content must be encrypted on the user's device, and the server must not possess the decryption key, so compromising the server alone is insufficient to read note plaintext. This objective does not cover compromised endpoints, malicious clients, leaked keys, exposed metadata, or implementation flaws.
- Cross-Platform: It must work on web browsers and desktop applications (Windows, macOS).
- Offline-First: Even without internet, users should be able to view, create, and edit notes. When they have internet, it should automatically sync to the cloud.
- Basic Features: Support Markdown syntax, and notes can be organized by folders."
The "devilish" aspects of this case study are:
- Cross-Platform (
Web+Desktop): This means we need to handle the differences between different runtime environments, making it an excellent training ground for "environmental constraints." - Offline-First (
Offline-First): This requires us to persist data locally and handle complex data synchronization and conflict resolution logic, placing high demands on "architectural constraints" and "process constraints." - End-to-End Encryption (
E2EE): This is an extremely serious security requirement. Any error in "encryption" logic can be catastrophic. This provides the most rigorous test for our "quality constraints" (especially testing).
We will use a common tech stack to build it:
- Core Logic: TypeScript (one codebase, run everywhere)
- Web Frontend: React
- Desktop: Electron
- Local Storage: IndexedDB (via a library like
Dexie.js) - Cloud Sync: A simple RESTful API backend (we will focus primarily on the frontend and core logic for this case; the backend will be simplified)
- Encryption Library:
libsodium-wrappers
14.2 Phase One: Documentation First, Establish the Constraint Layer
Goal: Before writing any line of application code, use documentation to build unshakable "mental guardrails" for AI and ourselves. This is the concentrated manifestation of architectural constraints.
Action: We create three core Markdown files in the project root directory.
1. Create AGENTS.md
We first define the role and code of conduct for the AI collaborating with us.
# AI Agent Directives: Project "Guardian Notes"
This document defines your persona and core principles for this project.
## Persona: Senior Security-Focused Engineer
You are to act as a Senior Software Engineer with a specialization in security and cross-platform application development. You are paranoid, meticulous, and pragmatic.
## Core Principles:
1. Security First, Always: Every line of code that handles user data must be viewed through a security lens. When in doubt, choose the more secure option.
2. Offline-First is Non-Negotiable: All features must be designed to work offline first. Cloud sync is an enhancement, not a dependency.
3. Simplicity over Complexity: Given the security-critical nature, prefer simple, well-understood algorithms and architectures over complex, "clever" ones.
4. Zero Trust for the Server: The server is considered a dumb, untrusted storage bucket. It should never see unencrypted user data or have access to decryption keys.
5. Strictly Typed: All code must be written in TypeScript with `strict` mode enabled. The `any` type is forbidden.
2. Create ARCHITECTURE.md
This is the project's "constitution." Here, we make the most critical, high-level technical decisions and delineate the "negative space."
# "Guardian Notes" - Architecture Document (v0.1)
This is the Single Source of Truth for our architecture.
## 1. Core Principles (Reiteration)
- End-to-End Encrypted (E2EE)
- Offline-First
- Cross-Platform (Web, Desktop)
## 2. High-Level Architecture
The application is divided into three layers:
1. Core Logic (Platform-Agnostic): A pure TypeScript module responsible for encryption, data management (CRUD), and sync logic. It has ZERO dependencies on any UI framework or platform-specific API.
2. Platform Adapters: Thin layers that connect the Core Logic to specific platforms (e.g., a React hooks-based adapter for the Web/Desktop UI, a REST API adapter for cloud sync).
3. UI Layer: The React components that consume the platform adapters.
## 3. The "Forbidden Zone" (Negative Constraints)
To enforce our principles, the following are STRICTLY FORBIDDEN:
- No Unencrypted Data on the Wire: Any data sent to the server API MUST be a pre-encrypted binary blob or ciphertext string.
- No Private Keys on the Server: The user's master decryption key must NEVER leave the client device. It may be stored, wrapped (encrypted with a password), in the client's local storage.
- Core Logic Cannot Access `window` or `document`: The Core Logic module is forbidden from importing or accessing any browser-specific or Electron-specific global objects. This ensures its platform-agnostic purity.
- UI Components Cannot Perform Direct Data-Access: All data operations (reading from/writing to the database, encryption) MUST go through the Core Logic via the adapter layer. UI components should be "dumb".
## 4. Key Decisions
- Encryption: We will use `libsodium-wrappers` for all cryptographic operations. The chosen algorithm will be `XChaCha20-Poly1305-IETF` for symmetric encryption.
- Local Storage: We will use `Dexie.js` as a wrapper around IndexedDB for robust local data persistence.
- Data Sync: The sync protocol will be state-based. The client sends its full encrypted data blob to the server, and the server replaces its old version. (Note: This is a simplification for the case study; a real app would use a more granular, operational-transform-based sync).
3. Create CHANGELOG.md
We initialize our "voyage log," writing the first entry for the upcoming development work.
# Changelog
## Unreleased
- Decision: Established the initial project structure and core architectural constraints. Defined AI agent persona.
- Next Step: Begin implementation of the "Core Logic" layer, starting with the encryption module.
Phase Retrospective: We spent about an hour (an indicative figure, depending on project complexity) without writing any application code. But what we achieved was decisive. We:
- Set the Tone: Through
AGENTS.md, we let AI know this is a serious, security-first project, not an ordinary CRUD application. - Built the Skeleton: Through
ARCHITECTURE.md, we made the most important, far-reaching technical decisions and established physical isolation (layering) to prevent code of different concerns from "polluting" each other. - Drew the Red Lines: Through "negative space" constraints, we proactively blocked the "shortcuts" and "bad smells" most likely to lead to project failure.
- Clarified the Starting Point: Through
CHANGELOG.md, we clearly know what to do next.
Now we have a solid "container." It is time to fill it with logic.
14.3 Phase Two: Assemble the Core Process, Enforce the "Three-Step" Approach
Goal: Implement the core functionality of the project -- local encryption, storage, and reading of notes. During this process, strictly follow the "Research -> Plan -> Execute" process constraints, forcing "slow thinking."
Scenario: We need to implement an EncryptionService that handles key generation, encryption, and decryption of text.
Step One: Research
We cannot just let AI write code directly. First, we have it act as our "research assistant."
Your Question (in a new, clean session, first feed the three documents):
[Paste content of AGENTS.md, ARCHITECTURE.md, CHANGELOG.md]
Acknowledge and internalize. Our next step is to implement the encryption module.
Your Role: Act as the Senior Security-Focused Engineer defined in the agent directives.
Task: We have decided to use
libsodium-wrappers. Before we write code, conduct a brief research on the best practices for using this library for our specific use case (encrypting user text with a master key derived from a password).
- Key Derivation: What is the recommended function in libsodium for deriving a strong encryption key from a user's password? What parameters (like
salt,ops-limit,mem-limit) are involved, and what are sane defaults?- Encryption/Decryption: What is the specific function for symmetric encryption using
XChaCha20-Poly1305-IETF? What are the inputs (key, nonce, plaintext) and outputs? How should the nonce be generated and stored?Constraint: Do not provide a full implementation yet. Your focus is on providing the necessary background information and function signatures.
AI will return a detailed, security-warning-laden technical memo about crypto_pwhash (key derivation) and crypto_aead_xchacha20poly1305_ietf_encrypt (encryption). It will explain the importance of "salt" and "nonce."
Step Two: Plan
Based on the research results, we ask AI to design the "blueprint" for EncryptionService.
Your Question:
Excellent research. Now, let's design the API for our
EncryptionService.tsmodule.Task:
- Define the Interface: Propose a TypeScript interface named
IEncryptionServicethat exposes the necessary methods. These should include methods for:
- Generating a new master key.
- Deriving a key from a password (for login).
- Encrypting a string.
- Decrypting a ciphertext.
- Plan the Implementation: For each method in the interface, write a short, 1-2 sentence comment describing its implementation strategy based on your previous research (e.g., "This will use
crypto_pwhashto derive the key...").- Task Breakdown: Create a sequential task list for implementing this service.
Constraint: Again, provide only the interface, comments, and task list. No method bodies yet.
AI will return a clear interface definition and development plan. This "planning" process forces us to think about the module's "public contract" rather than prematurely sinking into implementation details.
Step Three: Execute
Now, all the thinking and design work is done. We enter the "high-speed coding" phase. We hand over each task in the task list to AI one by one.
Your Question:
I approve the design. Let's start with Task 1: "Implement the
generateMasterKeymethod".Task: Write the full implementation for the
generateMasterKeymethod within a classEncryptionServicethat implementsIEncryptionService.Constraints:
- The key must be generated using
randombytes_buf.- The key should be returned in a secure, URL-safe base64 encoding.
- Adhere to all principles in
AGENTS.mdandARCHITECTURE.md.
AI returns a small, highly focused piece of code that conforms to all our constraints. We repeat this process to complete each method, such as encrypt and decrypt. During this process, we also have AI write comprehensive unit tests for each method and ensure test coverage meets the standard (initial intervention of quality constraints).
Phase Retrospective:
- We resisted the temptation to "directly have AI write encryption code."
- Through the "three-step" process, we decomposed a complex, security-sensitive task into controllable, reviewable small steps.
- The final code was not something AI "came up with on a whim," but a product of our joint research and design with AI, carefully considered. Its reliability far exceeds the "one-shot" generation approach.
14.4 Phase Three: Environment Debugging, Using Telemetry Logs to Conquer Platform Differences
Goal: Integrate the core logic into two different platforms, Web and Electron, and resolve the inevitably arising "environment-dependent" issues. This is where environmental constraints meet real-world application.
Scenario: In the Electron desktop app, we find that note-saving is occasionally extremely slow, even causing the app to freeze. But on the Web side, the same operation is very smooth.
This is a classic "environment-dependent" bug. The code is the same (our Core Logic), but the performance differs dramatically across environments.
Wrong Process: Ask AI: "My Electron app is very slow, but the Web is not. Why?" This is an unanswerable question. AI can only guess.
Correct Process (Telemetry-Driven):
- Implant Telemetry Probes: We realize we know nothing about the internal workings of this "save" black box. We decide to implant detailed structured logging in the "save note" flow of the Core Logic.
Your Question (to AI):
"We need to add detailed performance logging to our
saveNotefunction inNoteService.ts. Act as a Senior SRE. Modify the function to log structured events at key stages. The logs must includetrace_id, timestamps, and relevant context likenote_id."The stages to log are:
SAVE_NOTE_STARTEDENCRYPTION_STARTEDENCRYPTION_FINISHED(log duration)LOCAL_DB_WRITE_STARTEDLOCAL_DB_WRITE_FINISHED(log duration)SAVE_NOTE_FINISHED(log total duration)
Gather Evidence in the Real Environment: In the Electron app, open the developer tools, perform a few slow "save" operations, and then copy the complete structured JSON log stream from the console.
Reverse Feed the Logs:
Your Question (to AI):
Context: We are debugging a performance issue in our Electron app. Here is the full log stream from a single, slow
saveNoteoperation.Your Role: Act as a Performance Engineer specializing in Electron and browser storage.
Log Data:
[ {"event": "SAVE_NOTE_STARTED", "trace_id": "xyz", ...}, {"event": "ENCRYPTION_STARTED", ...}, {"event": "ENCRYPTION_FINISHED", "duration_ms": 50, ...}, {"event": "LOCAL_DB_WRITE_STARTED", ...}, {"event": "LOCAL_DB_WRITE_FINISHED", "duration_ms": 8500, ...}, {"event": "SAVE_NOTE_FINISHED", "total_duration_ms": 8550, ...} ]Analysis Request:
- Based on the log data, what is the exact bottleneck?
- The same operation in the Chrome browser takes only 100ms for the DB write. Why would an IndexedDB write be over 80 times slower in Electron compared to Chrome, given they use the same V8 engine?
- Propose a specific solution for this Electron-specific issue.
AI's Precise Diagnosis: After receiving this quantified data, AI's "thinking" process would be:
Locate the bottleneck: The log clearly shows that the vast majority of the 8.5 seconds is spent on
LOCAL_DB_WRITE. Encryption is fast.Activate specialized knowledge: AI's knowledge base contains a wealth of information about performance differences between Electron and the Web. It knows that Electron's renderer process and the sandboxed browser environment may differ in underlying I/O models and disk interaction methods.
Propose a hypothesis: It would propose a hypothesis worth testing: "In Electron, frequently writing small batches of data to IndexedDB (which is backed by the filesystem) can be affected by main process I/O bottlenecks or real-time antivirus scanning, causing drastic performance degradation. Chrome has deeper optimizations for this. A common solution is to batch multiple small writes into one large write. This is a hypothesis to be validated with data, not a settled conclusion."
Fix and Verify: Based on AI's suggestion, we modify the code to use
Dexie.js'sbulkPut()API to cache multiple save operations and write them to the database in one go. Running again, the Electron save speed returns to the millisecond level, matching the Web.
Phase Retrospective:
- Faced with a "black box" environmental problem, we did not fall into guesswork.
- We used "telemetry" to "data-fy" and "visualize" the problem.
- We leveraged AI's vast, cross-domain knowledge base to precisely interpret this data, finding the "demon" hidden in the platform differences.
14.5 Phase Four: Refactoring Optimization, Subtracting While Holding the Line with Tests
Goal: The core functionality of the project is complete. Now we need to "purify" it, removing the technical debt generated during development and optimizing the structure, while ensuring no existing functionality is broken. This is the practice of quality constraints and regular garbage collection.
Scenario: Our NoteService.ts module has become somewhat bloated after multiple iterations. It contains a mix of data operations, encryption calls, and some initial sync logic. We want AI to refactor it, splitting it into more cohesive modules.
Action:
- Establish "Anti-Regression" Baselines:
Before refactoring, we build solid defenses for
NoteService.ts.
- Functional Defense: We use AI to write unit tests with 100% branch coverage for all public methods of
NoteService.ts. We run them, and all tests pass. This is our "functional correctness baseline." - Performance Defense: We write benchmarks for the most critical functions,
saveNoteandloadNotes, and record their average execution times under the current implementation. This is our "performance baseline."
- Authorize AI to "Dance in Chains": Now, we can safely let AI perform bold refactoring.
Your Question (to AI):
Context: We need to refactor our
NoteService.tsmodule. It has grown too large.Your Role: Act as a Senior Software Architect, obsessed with the Single Responsibility Principle (SRP).
Task:
- Propose a Refactoring Plan: Analyze the current
NoteService.tsand propose a plan to split it into smaller, more cohesive modules (e.g.,NoteRepository.tsfor data access,SyncService.tsfor sync logic, etc.).- Execute the Refactoring: Once I approve the plan, provide the code for the new modules and the refactored
NoteService.ts.ANTI-REGRESSION CONTRACT (ABSOLUTE & NON-NEGOTIABLE):
- No Functional Regression: The refactored code must pass all existing unit tests for
NoteService.tswithout any modification to the test files themselves.- No Performance Regression: The performance of the key operations must remain within 5% of our established baselines.
- Clean Up: After the refactoring, run
ts-pruneto identify and remove any now-unused helper functions or imports from the old module.
- AI Execution and Automated Acceptance: AI receives the instruction and starts working. It might split a 500-line file into three new files of around 100 lines each. This process would be extremely tedious and error-prone if done manually.
When AI completes the refactoring, we perform the acceptance:
- Gate One: Unit Tests. We run the old test suite against the new code. If any test fails, we reverse-feed the failure log to AI for self-repair.
- Gate Two: Performance Tests. We run the benchmarks. If a regression is detected, we feed the regression report back to AI for optimization.
- Gate Three: Garbage Collection. We run
ts-pruneanddepcheckto thoroughly clean up the "dead code" and "orphan dependencies" generated after AI's refactoring.
Phase Retrospective:
- We successfully completed a complex, risky refactoring, but the entire process was conducted with confidence.
- Our confidence came not from "blind trust" in AI, but from the automated, impassable "quality grid" we had established.
- The result of the refactoring was not just cleaner code. Through "garbage collection," we made the codebase smaller and purer than before the refactoring. We achieved true "reverse growth."
[Project Retrospective] Decision Points and Mindsets at Each Phase
Looking back on our complete voyage from zero to one, we can summarize the most important "mindsets" and "decision points" for each phase.
| Phase | Core Task | Key Decision Point / Mindset | Constraint System |
|---|---|---|---|
| One: Documentation First | Build consensus, define boundaries | "Slow is fast": The 1 hour spent on documentation saves 10 hours of rework later. "First think about what not to do": Negative space constraints reflect architectural wisdom better than describing features in the positive. | Architectural Constraints |
| Two: Core Development | Transform design into code | "Resist the temptation of 'one-shot'": Enforce the "three-step" process to redirect AI's computing power from "fast coding" to "deep thinking." | Process Constraints |
| Three: Environment Debugging | Solve platform differences and "black box" problems | "Don't 'talk' about the problem with AI. 'Feed' it data": No verbal description is more convincing than raw, structured telemetry logs. | Environmental Constraints |
| Four: Refactoring Optimization | Fight entropy, improve quality | "Trust, but verify": Authorize AI to refactor boldly, but use automated, rigid test baselines to ruthlessly verify its results. "The codebase is a garden, not a warehouse": Regular pruning and purification reflect a senior engineer's value more than continuously piling on new features. | Quality Constraints |
Final Reflection: "Effective constraints" are not about limiting AI's creativity. On the contrary, they are meant to release AI's creativity in the safest and most efficient way.
Just like a turbulent river: without the constraint of riverbanks, it would only flood wantonly, eventually becoming a lifeless swamp. But with solid riverbanks (our constraint system), its immense power can be guided and focused, eventually flowing into the sea, or driving a water turbine generator to light up an entire world.
You are that "river manager." Having mastered the art of "constraint," you have mastered the secret to dancing with the most powerful productive force of this era.