Presented by The Growth Hunting Company
A lot of software engineering is applying the SDLC on existing systems. "All software development is maintenance".
Today I'm going to talk about building a system from scratch using the tools that you've learned in COMP1531.
This lecture is in some ways a revamp of a previous lecture "Building an MVP".
https://www.growthhunting.com.au/
We believe in the transformative power of education to unlock human potential and drive positive change. Our mission is to empower individuals, organisations, and communities through continuous learning and development.
Where we're at in April 2025.
[DISCOVER] Ideation
It all starts with an idea.
[DISCOVER] Requirements engineering
Take the time to understand what problem it is you're trying to solve and why it's worth solving.
[PLAN] Create an initial design to scope out requirements
Sometimes the best way to figure out what to build is to go and build it, and get it wrong.
December 2023
[TEAM] Project Kickoff
Teams' operation is a function of their context. Figure out what works for yours.
27 Dec 2023
[PLAN] Decide on your system design
27 Dec 2023
[BUILD] Let's get coding!
Express HTTP Server
app.post(
'/mps',
validateAndAuthenticateBuckets,
async (req: PressureStoryRequest, res: any) => {
try {
// Call update function
await updatePressureStoryBuckets(req.body)
res.send('Success')
} catch (err: any) {
console.log('❌ Error updating pressure story buckets:', err)
res.status(500).send('Error saving data')
}
}
)
Package management with NPM
{
"name": "gzgs-api",
"version": "1.0.0",
"description": "",
"main": "app.js",
"scripts": {
"start:local": "npm run build:ci && npm run start",
"start": "node dist/api/src/app.js",
"dev": "nodemon --watch src --exec ts-node src/api/src/app.ts",
"build": "./build.sh",
"build:ci": "tsc",
"test": "jest",
"lint": "./node_modules/.bin/eslint src/**/*.ts*",
"lint:fix": "npx prettier -w . && ./node_modules/.bin/eslint src/**/*.ts* --fix"
},
"author": "sneaky-patriki",
"license": "ISC",
"dependencies": {
"@react-email/render": "^0.0.15",
"@types/node": "^20.10.5",
"antd": "^5.17.4",
"bcryptjs": "^2.4.3",
"cors": "^2.8.5",
"dotenv": "^16.4.7",
"emailjs-com": "^3.2.0",
...
}
}
Dynamic verification with Jest
Static verification with TypeScript
Linting with ESLint & Prettier
At some point, we'll fix these warnings, but it's not the most important thing... right now
Persistence
export const CauseBucket = sequelize.define('CauseBucket', {
orgId: DataTypes.STRING,
cause: DataTypes.STRING
})
export const AppearsBucket = sequelize.define('AppearsBucket', {
orgId: DataTypes.STRING,
appears: DataTypes.STRING
})
export const ReasonBucket = sequelize.define('ReasonBucket', {
orgId: DataTypes.STRING,
reason: DataTypes.STRING
})
Sequelize: A NodeJS library that allows you to interact with a database engine
PostgreSQL: A database engine that allows you to create relational models and store data persistently
Authentication & Authorisation
export const authenticateMPS = async (
userPassword: string,
salt: string
): Promise<{ sessionToken: string } | null> => {
const adminPassword = process.env.MPS_ADMIN_PASSWORD
if (!adminPassword) {
throw new Error('Admin password is not set')
}
const hashedActualPassword = await bcrypt.hash(adminPassword, salt)
if (userPassword !== hashedActualPassword) {
return null
}
const adminToken = jwt.sign(
{ orgId: null, isAdmin: true, timestamp: Date.now() },
JWT_SECRET,
{ expiresIn: '48h' }
)
await MPSSession.create({
orgId: 'admin',
sessionToken: adminToken
})
return { sessionToken: adminToken }
}
LLM Integration
import OpenAI from 'openai'
const modelId = 'gpt-3.5-turbo'
export const aiWritePressureStory = async (
pressureStory: string
): Promise<string | null> => {
const result = await openai.chat.completions.create({
model: modelId,
messages: [
{
role: 'user',
content: pressureStory
}
]
})
return result.choices[0].message.content
}
const getPrompt = (topic) => {
topic = topic.toLowerCase().includes("effect")
? topic.toLowerCase().includes("on me")
? "EffectMe"
: "EffectOthers"
: topic;
const prompt = `Write a concise paragraph in first person.
Begin with ${promptMessage[topic]} and include ${prev.join(", ")}.
Do not give suggestions only expand on the prompt.
Do not duplicate the content.
Use natural sentence casing.
Make the paragraph flow naturally.`;
if (topic === "Strategy") {
return `${prompt}. Use "I need" language.`;
} else if (topic === "Support") {
return `${prompt}. Write from the perspective of the support I need from those around me is...`;
} else {
return `${prompt}. Don't talk about how I am working through/navigating this pressure.`;
}
};
Using GitHub for branches, commits and PR reviews
Continuous Integration via GitHub Actions
Heroku for backend, Vercel for frontend.
The domain is managed separately, but Vercel can link to a domain.
[DEPLOY] Deploy a simple version of your software early and make it part of the development lifecycle.
Jira for task management, Confluence for documentation management, Atlas for project tracking
[TEAM] Establish the source of truth which your team updates to keep itself on track.
August 2024
December 2024
[CONTINUOUS FEEDBACK] Validate your software with the people who are using it
January 2025
[OPERATE & OBSERVE] Good software is unexciting when you release it :)
February 2025 - My Pressure Story used in a live Growth Hunting Session
[DISCOVER] We build software to create value. Always think about what real life process your software is helping oil.
[TEAM] As you develop operational maturity, you will be able to scale the development of your software
Yesterday
#1: Focus on the most important thing, one at a time.
#2: Learn to think like your users.
#3: Don't pigeon hole yourself as an engineer.