WEBVTT

1
00:00:00.000 --> 00:00:01.680
Hey, in this video, we're going to build

2
00:00:01.680 --> 00:00:03.840
a newsletter blog that sends out an email

3
00:00:03.840 --> 00:00:06.220
to your users every Friday with a summary

4
00:00:06.220 --> 00:00:08.560
of the articles that were written that week.

5
00:00:08.560 --> 00:00:09.920
And we're not going to use a SaaS

6
00:00:09.920 --> 00:00:11.160
subscription to send the emails.

7
00:00:11.160 --> 00:00:14.500
We're just going to use raw Amazon AWS SES,

8
00:00:14.500 --> 00:00:16.580
which costs a couple cents per month to send

9
00:00:16.580 --> 00:00:18.560
emails. Everything else is going to be built

10
00:00:18.560 --> 00:00:20.460
in Elements, completely customized

11
00:00:20.460 --> 00:00:22.220
to exactly what we want.

12
00:00:22.740 --> 00:00:25.560
And the reason that you might do this is if

13
00:00:25.560 --> 00:00:27.140
you're building an application for your

14
00:00:27.140 --> 00:00:29.020
business that has many different parts.

15
00:00:29.020 --> 00:00:31.160
One of the common use cases for Elements

16
00:00:31.160 --> 00:00:32.840
is to combine a bunch of different

17
00:00:32.840 --> 00:00:34.620
SaaS subscriptions and various business

18
00:00:34.620 --> 00:00:36.220
applications that you have spread out all

19
00:00:36.220 --> 00:00:38.160
over the place into one application

20
00:00:38.160 --> 00:00:41.180
that you can run and build with something

21
00:00:41.180 --> 00:00:44.240
like Claude Code or an AI agent and get

22
00:00:44.240 --> 00:00:46.660
it to do exactly what you want to do.

23
00:00:46.660 --> 00:00:48.340
And you can have one database where

24
00:00:48.340 --> 00:00:50.280
all of your customer information is,

25
00:00:50.280 --> 00:00:51.940
your payments and invoices,

26
00:00:51.940 --> 00:00:53.780
your customer relationship management,

27
00:00:53.780 --> 00:00:55.020
your blog and newsletter.

28
00:00:55.020 --> 00:00:56.480
All of that can be combined

29
00:00:56.480 --> 00:00:57.940
into one application.

30
00:00:59.020 --> 00:01:00.580
If you're just sending email

31
00:01:00.580 --> 00:01:02.540
newsletters and that's all you're doing,

32
00:01:02.540 --> 00:01:04.040
there's probably a SaaS subscription

33
00:01:04.040 --> 00:01:05.520
that would be better suited for that.

34
00:01:05.520 --> 00:01:06.760
If you're building an application where

35
00:01:06.760 --> 00:01:08.440
you want to have complete control over

36
00:01:08.440 --> 00:01:10.140
it and you want it to be exactly the way,

37
00:01:10.140 --> 00:01:11.820
to look exactly the way that you want

38
00:01:11.820 --> 00:01:13.520
and to add features that you want,

39
00:01:13.520 --> 00:01:15.620
this is a really fantastic way to do that.

40
00:01:15.620 --> 00:01:16.880
So without further ado, let's build

41
00:01:16.880 --> 00:01:19.060
the application and then we'll take a look

42
00:01:19.060 --> 00:01:20.940
through the code and see what the agent

43
00:01:20.940 --> 00:01:23.040
actually produced and why it's maintainable

44
00:01:23.040 --> 00:01:25.320
and a great way to build applications.

45
00:01:25.680 --> 00:01:27.020
Now, let me talk about my setup.

46
00:01:27.020 --> 00:01:29.160
I'm gonna create a Visual Studio Code

47
00:01:29.160 --> 00:01:31.440
application here, type new app,

48
00:01:31.440 --> 00:01:33.260
which is the first one that pops up,

49
00:01:33.260 --> 00:01:34.980
but if it doesn't, you can type new app,

50
00:01:34.980 --> 00:01:37.900
click that, and we'll call this blog.

51
00:01:38.500 --> 00:01:40.700
Now, my setup is Visual Studio Code,

52
00:01:40.700 --> 00:01:42.680
where I've got Claude Code in the lower left

53
00:01:42.680 --> 00:01:45.020
and a terminal up in the upper right.

54
00:01:45.340 --> 00:01:47.020
If you're using a different

55
00:01:47.020 --> 00:01:48.720
setup, it's fine.

56
00:01:48.720 --> 00:01:50.580
Elements actually doesn't care what you use.

57
00:01:50.580 --> 00:01:52.460
Elements is a command line tool

58
00:01:52.460 --> 00:01:54.100
with a project server that runs

59
00:01:54.100 --> 00:01:55.740
an application framework code

60
00:01:55.740 --> 00:01:57.620
that is used to write the application.

61
00:01:57.920 --> 00:01:59.200
If you want to write it in the terminal,

62
00:01:59.200 --> 00:02:00.620
you can do that. If you want to use Visual

63
00:02:00.620 --> 00:02:02.640
Studio Code, you can use that.

64
00:02:02.640 --> 00:02:04.300
If you're using something like Claude Code

65
00:02:04.300 --> 00:02:06.560
Desktop, that will work just as well.

66
00:02:06.560 --> 00:02:08.500
As soon as you have Elements installed,

67
00:02:08.500 --> 00:02:09.760
the various editors will become aware

68
00:02:09.760 --> 00:02:12.060
of it and will be able to help you through.

69
00:02:12.060 --> 00:02:13.660
And if you're just using Claude Code

70
00:02:13.660 --> 00:02:15.300
in the terminal, it will know

71
00:02:15.300 --> 00:02:16.940
that Elements is installed and it will help

72
00:02:16.940 --> 00:02:18.520
you figure out how to create applications.

73
00:02:18.520 --> 00:02:20.560
So you can always just ask your agent

74
00:02:20.560 --> 00:02:21.620
what to do if you're not sure.

75
00:02:21.620 --> 00:02:24.360
But in our tutorials, we'll use Visual

76
00:02:24.360 --> 00:02:26.680
Studio Code, which is free and open source,

77
00:02:26.680 --> 00:02:27.780
made by Microsoft. I think it's

78
00:02:27.780 --> 00:02:29.620
a great way to build these applications.

79
00:02:29.620 --> 00:02:30.820
So whenever we start a new application

80
00:02:30.820 --> 00:02:32.080
in Elements, up in the upper left

81
00:02:32.080 --> 00:02:34.740
in the terminal, I'll type elements start,

82
00:02:34.740 --> 00:02:36.640
and that's going to boot up the application

83
00:02:36.640 --> 00:02:38.800
server, and it should open up the browser

84
00:02:38.800 --> 00:02:40.820
in the right, and you can see our basic demo

85
00:02:40.820 --> 00:02:43.440
application running there on the right.

86
00:02:43.440 --> 00:02:45.920
And if the state is green, okay, that means

87
00:02:45.920 --> 00:02:47.560
the application is good to go, and if it's

88
00:02:47.560 --> 00:02:49.620
red, it means there's some kind of error.

89
00:02:49.620 --> 00:02:51.620
Either your agent produced an error

90
00:02:51.620 --> 00:02:53.440
or you produced an error and you need

91
00:02:53.440 --> 00:02:55.060
to correct something. So you always have

92
00:02:55.060 --> 00:02:57.380
a visual indication of how things are going.

93
00:02:57.380 --> 00:02:59.020
Now in the lower left I've got Claude Code,

94
00:02:59.020 --> 00:03:00.620
because Elements, our company,

95
00:03:00.620 --> 00:03:02.420
has a subscription with Claude Code,

96
00:03:02.420 --> 00:03:04.500
but you can use any model you want.

97
00:03:04.500 --> 00:03:05.840
If you want to use the standard Visual

98
00:03:05.840 --> 00:03:08.040
Studio Code agent user interface, you can do

99
00:03:08.040 --> 00:03:09.820
that. If you want to use Claude Code,

100
00:03:09.820 --> 00:03:11.440
the extension, which is what I have here,

101
00:03:11.440 --> 00:03:13.300
you can do that as well.

102
00:03:13.300 --> 00:03:15.280
So I've got Claude Code, Opus 5.5.

103
00:03:15.280 --> 00:03:16.740
I have it on fast mode so we can go

104
00:03:16.740 --> 00:03:18.320
a little bit faster, although that would

105
00:03:18.320 --> 00:03:20.120
be a little bit more expensive if you're

106
00:03:20.120 --> 00:03:21.700
going to do it that way. But we should

107
00:03:21.700 --> 00:03:23.640
end up with the same result either way.

108
00:03:23.640 --> 00:03:25.340
Okay, let's prompt our way through this.

109
00:03:25.340 --> 00:03:26.840
I'm going to say, I want to build

110
00:03:26.840 --> 00:03:28.600
a blog that has a weekly

111
00:03:28.600 --> 00:03:30.500
newsletter that goes out to users.

112
00:03:30.500 --> 00:03:33.440
The blog is available to anyone to see,

113
00:03:33.440 --> 00:03:36.060
but the newsletter only goes to subscribed

114
00:03:36.060 --> 00:03:37.800
users, users that have

115
00:03:37.800 --> 00:03:40.460
registered with an email and password.

116
00:03:40.840 --> 00:03:42.740
The newsletter should go out every Friday,

117
00:03:42.740 --> 00:03:44.320
and I only want to show users

118
00:03:44.320 --> 00:03:45.860
the new articles that have been created

119
00:03:45.860 --> 00:03:48.040
since the last newsletter went out.

120
00:03:48.040 --> 00:03:50.740
Don't send them a repeat or a set

121
00:03:50.740 --> 00:03:52.160
of articles, or if nothing was written,

122
00:03:52.160 --> 00:03:53.980
don't send them a blank email.

123
00:03:53.980 --> 00:03:55.740
Okay, I'll press enter

124
00:03:55.740 --> 00:03:58.220
and let Claude get to work.

125
00:04:01.960 --> 00:04:03.740
Now occasionally you'll see the state

126
00:04:03.740 --> 00:04:05.380
in the upper left turn to error,

127
00:04:05.380 --> 00:04:07.840
a red error, and that means that the agent's

128
00:04:07.840 --> 00:04:09.900
made a mistake, and it will fix it,

129
00:04:09.900 --> 00:04:11.840
because the Elements project server gives

130
00:04:11.840 --> 00:04:13.580
it feedback in real time, typically

131
00:04:13.580 --> 00:04:15.680
in microseconds, as soon as it asks,

132
00:04:15.680 --> 00:04:17.480
and it will tell it how to fix it.

133
00:04:17.480 --> 00:04:18.900
So the agent will fix the bug,

134
00:04:18.900 --> 00:04:20.680
and then you'll see the build change again,

135
00:04:20.680 --> 00:04:22.100
and the state will go back to green.

136
00:04:25.560 --> 00:04:26.840
All right, it looks like Claude finished

137
00:04:26.840 --> 00:04:28.940
the job. It took about 5 to 10 minutes,

138
00:04:28.940 --> 00:04:29.960
and it has a summary here

139
00:04:29.960 --> 00:04:31.540
saying that it's built it all.

140
00:04:31.540 --> 00:04:33.820
With 29 tests that pass, it clicked through

141
00:04:33.820 --> 00:04:35.500
the flow and made sure that it works using

142
00:04:35.500 --> 00:04:37.520
headless Chrome. It's a public blog.

143
00:04:37.520 --> 00:04:39.120
It's got accounts, a weekly newsletter

144
00:04:39.120 --> 00:04:41.060
that runs every Friday at 9 o'clock.

145
00:04:41.440 --> 00:04:42.960
No repeats, no blank emails.

146
00:04:42.960 --> 00:04:45.300
There's an admin page that only

147
00:04:45.300 --> 00:04:47.160
allows authenticated administrative users

148
00:04:47.160 --> 00:04:49.440
to create new posts and see

149
00:04:49.440 --> 00:04:50.900
other various administrative information,

150
00:04:50.900 --> 00:04:52.780
and all the various checks

151
00:04:52.780 --> 00:04:54.440
that it did to make sure that it works.

152
00:04:54.440 --> 00:04:55.780
There's a couple example accounts

153
00:04:55.780 --> 00:04:57.540
that it gives us that we can use to log in,

154
00:04:57.540 --> 00:04:59.120
and it shows us how we can sample

155
00:04:59.120 --> 00:05:00.560
the newsletter. So let's go take

156
00:05:00.560 --> 00:05:02.580
a look at what that email looks like.

157
00:05:02.580 --> 00:05:05.660
It looks like it's /dev/emails/newsletter,

158
00:05:05.660 --> 00:05:08.320
and this is what the email

159
00:05:08.320 --> 00:05:09.840
will look like to the users.

160
00:05:09.840 --> 00:05:12.100
It looks like there's the two

161
00:05:12.100 --> 00:05:13.700
posts that were created, and then

162
00:05:13.700 --> 00:05:16.100
an unsubscribe button down at the bottom.

163
00:05:16.100 --> 00:05:17.540
Let's click through and just make sure

164
00:05:17.540 --> 00:05:19.120
that everything works. I can click a post.

165
00:05:19.120 --> 00:05:21.620
That looks great. And go back to the post,

166
00:05:21.620 --> 00:05:23.220
and let's make sure that I can sign in.

167
00:05:23.220 --> 00:05:24.980
We've got an authentication form

168
00:05:24.980 --> 00:05:26.560
here that takes email and password.

169
00:05:26.560 --> 00:05:27.920
I can create an account,

170
00:05:27.920 --> 00:05:29.720
and all of this is baked in.

171
00:05:29.720 --> 00:05:31.280
We don't have any external services

172
00:05:31.280 --> 00:05:33.300
for authentication. We don't need

173
00:05:33.300 --> 00:05:34.820
a separate SaaS subscription for that.

174
00:05:34.820 --> 00:05:36.400
It just goes directly into your Postgres

175
00:05:36.400 --> 00:05:38.420
database. Before we move on from

176
00:05:38.420 --> 00:05:39.820
here, there's some other things we can do.

177
00:05:39.820 --> 00:05:41.840
I like this editorial theme,

178
00:05:41.840 --> 00:05:43.400
but we have many themes that are baked

179
00:05:43.400 --> 00:05:44.760
into Elements that you can choose.

180
00:05:44.760 --> 00:05:46.240
You can also have a designer create one

181
00:05:46.240 --> 00:05:48.360
for you, or ask the agent to mess around

182
00:05:48.360 --> 00:05:49.780
and give you something a little different.

183
00:05:49.780 --> 00:05:51.600
But let's play with a different theme.

184
00:05:51.600 --> 00:05:52.860
Let's try a different theme just

185
00:05:52.860 --> 00:05:54.240
so I can see what it looks like.

186
00:05:54.240 --> 00:05:55.760
Right here in the actual

187
00:05:55.760 --> 00:05:57.200
application, can you show me

188
00:05:57.200 --> 00:05:59.140
what the brutalist theme looks like?

189
00:05:59.780 --> 00:06:01.040
So if you want your users

190
00:06:01.040 --> 00:06:02.920
to feel extremely uncomfortable,

191
00:06:02.920 --> 00:06:04.820
you can give them this brutalist theme.

192
00:06:04.820 --> 00:06:07.340
Oh wow, yeah, that looks like an old

193
00:06:07.340 --> 00:06:10.020
80s style Nintendo game.

194
00:06:10.020 --> 00:06:11.220
Okay, so that's brutalist.

195
00:06:11.220 --> 00:06:14.060
Let's see what something like, let

196
00:06:14.060 --> 00:06:15.900
me try luxury next.

197
00:06:15.900 --> 00:06:17.980
So luxury might be something like a,

198
00:06:17.980 --> 00:06:19.900
oh, that looks kind of cool.

199
00:06:19.900 --> 00:06:22.140
That looks like maybe what a doctor's office

200
00:06:22.140 --> 00:06:24.340
website would look like. All right, let's

201
00:06:24.340 --> 00:06:25.800
just do one more while we're playing.

202
00:06:25.800 --> 00:06:28.680
Show me the playful theme.

203
00:06:28.680 --> 00:06:31.780
All right, not bad.

204
00:06:31.780 --> 00:06:33.120
A little bit more playful,

205
00:06:33.120 --> 00:06:35.400
playful rounded buttons,

206
00:06:35.400 --> 00:06:37.000
a little bit of a purple background.

207
00:06:37.000 --> 00:06:38.580
And finally,

208
00:06:39.100 --> 00:06:41.120
take me back to editorial.

209
00:06:41.120 --> 00:06:42.520
I think that one looks the best.

210
00:06:43.460 --> 00:06:45.140
Next up, let's ask Claude how much

211
00:06:45.140 --> 00:06:46.980
this will cost and what we have to do

212
00:06:46.980 --> 00:06:48.960
to actually send these emails.

213
00:06:48.960 --> 00:06:50.860
Right now we've just been sending them

214
00:06:50.860 --> 00:06:52.620
locally on our local server,

215
00:06:52.620 --> 00:06:54.640
but they're not actually going out.

216
00:06:54.640 --> 00:06:56.600
So let's ask: what would it cost

217
00:06:56.600 --> 00:06:59.240
to deploy this application and to use

218
00:06:59.240 --> 00:07:01.300
Amazon SES or the other,

219
00:07:01.300 --> 00:07:04.340
any other recommended service, to actually

220
00:07:04.340 --> 00:07:07.320
send these emails on a monthly basis?

221
00:07:07.320 --> 00:07:08.980
Assume I've got a couple hundred,

222
00:07:08.980 --> 00:07:11.600
maybe a couple thousand subscribers.

223
00:07:12.060 --> 00:07:14.160
Claude's gonna go look up the actual prices

224
00:07:14.160 --> 00:07:16.380
that exist and give me a fairly accurate,

225
00:07:16.380 --> 00:07:18.680
as of today, price for what it would cost

226
00:07:18.680 --> 00:07:21.020
to host this application myself and to send

227
00:07:21.020 --> 00:07:23.340
emails on a monthly basis. Okay, a minute

228
00:07:23.340 --> 00:07:25.080
or two later we get back our assessment,

229
00:07:25.080 --> 00:07:27.820
and Claude recommends that at this volume,

230
00:07:27.820 --> 00:07:29.780
it recommends using AWS, and that would cost

231
00:07:29.780 --> 00:07:32.240
$26 a month all in to host the application,

232
00:07:32.240 --> 00:07:33.920
plus to send the emails,

233
00:07:33.920 --> 00:07:35.880
which would be under $1 per month.

234
00:07:35.880 --> 00:07:38.260
Which shows the server size you would need,

235
00:07:38.260 --> 00:07:40.980
the disk size, what it would cost to get

236
00:07:40.980 --> 00:07:42.780
a public IP address, the managed Postgres,

237
00:07:42.780 --> 00:07:45.860
and so you're at about $25, maybe $26.

238
00:07:46.320 --> 00:07:47.980
And then down here in the table it will show

239
00:07:47.980 --> 00:07:49.780
the different price for sending email

240
00:07:49.780 --> 00:07:51.420
for 200 subscribers versus

241
00:07:51.420 --> 00:07:53.800
2,000 subscribers as an example.

242
00:07:53.800 --> 00:07:56.060
So, Amazon SES is by far

243
00:07:56.060 --> 00:07:58.380
the cheapest at 100

244
00:07:58.380 --> 00:08:01.360
to even a couple thousand subscribers.

245
00:08:01.360 --> 00:08:04.260
You're going to be at under $1 per month.

246
00:08:04.620 --> 00:08:06.800
So is $26 a month worth it?

247
00:08:06.800 --> 00:08:08.220
I think it is if you want to have

248
00:08:08.220 --> 00:08:09.840
total control over the application,

249
00:08:09.840 --> 00:08:11.580
what it looks like, and if you're building

250
00:08:11.580 --> 00:08:12.960
particularly an integrated application

251
00:08:12.960 --> 00:08:14.460
for your business that has newsletter

252
00:08:14.460 --> 00:08:16.220
or blogs as a part of that,

253
00:08:16.220 --> 00:08:17.760
then it's going to make a lot of sense.

254
00:08:17.760 --> 00:08:19.400
You'll likely save a lot of money.

255
00:08:19.400 --> 00:08:21.120
Now, when you're ready to set up SES,

256
00:08:21.120 --> 00:08:22.460
just ask Claude to do that,

257
00:08:22.460 --> 00:08:24.800
or your agent to do it, say I'm ready to go,

258
00:08:24.800 --> 00:08:26.580
and it will walk you through the process

259
00:08:26.580 --> 00:08:28.240
of setting up an account if you don't have

260
00:08:28.240 --> 00:08:29.920
one already. And if you do already have

261
00:08:29.920 --> 00:08:31.760
an account on AWS, it will use

262
00:08:31.760 --> 00:08:33.900
the command line interface to automatically

263
00:08:33.900 --> 00:08:35.520
configure it and get you set up.

264
00:08:35.520 --> 00:08:37.360
So within five to ten minutes, you should

265
00:08:37.360 --> 00:08:39.820
be able to send emails live on the internet.

266
00:08:39.820 --> 00:08:40.880
Now some people are worried about

267
00:08:40.880 --> 00:08:42.760
deliverability. There's a lot of,

268
00:08:42.760 --> 00:08:44.380
I think, a bit of fear mongering out

269
00:08:44.380 --> 00:08:46.540
there about deliverability. It is important.

270
00:08:46.540 --> 00:08:47.860
You don't want to end up in people's spam

271
00:08:47.860 --> 00:08:49.860
folders, and you want to be able

272
00:08:49.860 --> 00:08:51.780
to deliver your emails. The best way to do

273
00:08:51.780 --> 00:08:53.900
that is to use a service like SES.

274
00:08:54.500 --> 00:08:55.980
So you're not sending from an email server

275
00:08:55.980 --> 00:08:57.480
from your laptop, for example.

276
00:08:57.480 --> 00:08:59.900
You're actually using a service to do it. So

277
00:08:59.900 --> 00:09:02.200
that gets you about at least halfway there.

278
00:09:02.680 --> 00:09:04.380
Then the agent, whether it's

279
00:09:04.380 --> 00:09:06.320
Claude or Codex or whatever you're using,

280
00:09:06.320 --> 00:09:10.040
will add some records to your,

281
00:09:10.040 --> 00:09:13.620
some records to your domain

282
00:09:13.620 --> 00:09:15.920
that will help it become more trusted.

283
00:09:16.360 --> 00:09:18.120
It's very easy to do, and any agent can do

284
00:09:18.120 --> 00:09:20.000
it. So after that you should

285
00:09:20.000 --> 00:09:21.580
be fine as long as you're not spamming

286
00:09:21.580 --> 00:09:23.740
people or sending, you know,

287
00:09:23.740 --> 00:09:26.060
letting bots send emails to people.

288
00:09:26.060 --> 00:09:27.280
You'll be fine.

289
00:09:27.280 --> 00:09:29.600
Claude will, or your agent will,

290
00:09:29.600 --> 00:09:32.400
help you to design forms so that you can't,

291
00:09:32.400 --> 00:09:34.080
so that, so the bots can't harvest

292
00:09:34.080 --> 00:09:35.780
your forms or put email addresses into

293
00:09:35.780 --> 00:09:37.260
your form, so that you don't spam people.

294
00:09:37.260 --> 00:09:38.940
As long as you don't do those things,

295
00:09:38.940 --> 00:09:40.720
you'll be fine. You don't need a special

296
00:09:40.720 --> 00:09:43.740
service to get you to deliverability.

297
00:09:43.740 --> 00:09:45.560
You'll get that essentially for free just

298
00:09:45.560 --> 00:09:47.960
by using Amazon. Okay, next up, let's go

299
00:09:47.960 --> 00:09:50.100
take a look at what code was produced here.

300
00:09:50.100 --> 00:09:51.680
What did Elements actually do under

301
00:09:51.680 --> 00:09:53.360
the hood? Why was the agent

302
00:09:53.360 --> 00:09:55.000
able to build this so quickly?

303
00:09:55.000 --> 00:09:56.480
And why is it a maintainable

304
00:09:56.480 --> 00:09:58.140
app that you can hand to another agent

305
00:09:58.140 --> 00:10:00.560
or to a team of humans after this?

306
00:10:00.560 --> 00:10:02.060
Let's take a look at some of the source code

307
00:10:02.060 --> 00:10:04.460
under the hood so you can see how this was

308
00:10:04.460 --> 00:10:06.620
built and why Elements is such an effective

309
00:10:06.620 --> 00:10:09.000
platform for agents to build on top of.

310
00:10:09.000 --> 00:10:10.580
To start, we'll look in the application

311
00:10:10.580 --> 00:10:12.860
folder where all of your application code

312
00:10:12.860 --> 00:10:14.500
is, and we'll look in the migrations folder.

313
00:10:14.500 --> 00:10:16.900
This is how the agent

314
00:10:16.900 --> 00:10:20.180
is going to add and change your database.

315
00:10:20.180 --> 00:10:22.900
It's a very structured way to modify

316
00:10:22.900 --> 00:10:25.160
a database over time so that the agent

317
00:10:25.160 --> 00:10:27.140
isn't accidentally messing up your database

318
00:10:27.140 --> 00:10:29.460
or dropping it or things like that.

319
00:10:29.460 --> 00:10:30.760
And for a migration file,

320
00:10:30.760 --> 00:10:32.820
they're written in raw SQL.

321
00:10:32.820 --> 00:10:35.300
So you can see over here, the raw SQL, this

322
00:10:35.300 --> 00:10:37.720
is creating a couple of stored procedures.

323
00:10:37.720 --> 00:10:39.180
This is the users table.

324
00:10:39.180 --> 00:10:40.440
It has the password hash

325
00:10:40.440 --> 00:10:42.160
in it and a couple other things going on.

326
00:10:42.160 --> 00:10:45.120
And so, this is our baseline schema.

327
00:10:45.580 --> 00:10:47.520
And what will happen is the agent will write

328
00:10:47.520 --> 00:10:49.540
SQL, and it writes SQL very well.

329
00:10:49.540 --> 00:10:51.340
It doesn't need to learn an ORM in order

330
00:10:51.340 --> 00:10:53.660
to write this, some kind of abstraction.

331
00:10:53.660 --> 00:10:55.060
It just writes SQL, and it has a lot

332
00:10:55.060 --> 00:10:56.540
of SQL in its training data.

333
00:10:56.540 --> 00:10:58.060
So it does that very, very well.

334
00:10:58.380 --> 00:10:59.760
Elements will take care of automatically

335
00:10:59.760 --> 00:11:02.120
applying this to the database,

336
00:11:02.120 --> 00:11:03.440
and it does it in real time.

337
00:11:03.440 --> 00:11:05.520
As soon as the file is saved, it applies

338
00:11:05.520 --> 00:11:07.200
the migration immediately to the database.

339
00:11:07.200 --> 00:11:09.020
And if it changes, Elements takes care

340
00:11:09.020 --> 00:11:10.780
of syncing that change as well.

341
00:11:10.780 --> 00:11:12.140
And on deployment,

342
00:11:12.140 --> 00:11:14.980
database migrations are applied very safely,

343
00:11:14.980 --> 00:11:18.020
first to the test database and then to the

344
00:11:18.020 --> 00:11:20.560
application database only if that succeeds.

345
00:11:21.300 --> 00:11:23.480
These migrations are run in a transaction

346
00:11:23.480 --> 00:11:25.180
by default, which means if anything in here

347
00:11:25.180 --> 00:11:27.660
fails, it automatically rolls back.

348
00:11:27.660 --> 00:11:29.280
Now the second migration

349
00:11:29.280 --> 00:11:31.440
that it created is kind of interesting

350
00:11:31.440 --> 00:11:33.560
because it's our seed data.

351
00:11:33.560 --> 00:11:34.740
And if you notice this up here,

352
00:11:34.740 --> 00:11:37.800
there's a build tag here called @migration,

353
00:11:38.260 --> 00:11:39.780
and it says that this migration

354
00:11:39.780 --> 00:11:41.900
is for the development environment only.

355
00:11:41.900 --> 00:11:44.080
And this allows us to insert some seed

356
00:11:44.080 --> 00:11:46.140
data into the users table.

357
00:11:46.140 --> 00:11:47.940
That is what we were seeing

358
00:11:47.940 --> 00:11:50.040
as the example data in our application.

359
00:11:50.040 --> 00:11:51.640
So this is really helpful when you're

360
00:11:51.640 --> 00:11:54.080
building. You can put seed data and make

361
00:11:54.080 --> 00:11:56.820
it as part of the normal migration process.

362
00:11:56.820 --> 00:11:58.220
Next up, let's look in the pages folder

363
00:11:58.220 --> 00:12:00.440
and check the accounts folder.

364
00:12:00.440 --> 00:12:01.840
And this is going to be one of the pages

365
00:12:01.840 --> 00:12:03.100
that maps to the account URL.

366
00:12:03.100 --> 00:12:05.340
If I open up the eHTML,

367
00:12:05.340 --> 00:12:07.660
eHTML stands for Elements HTML,

368
00:12:08.140 --> 00:12:09.520
it's an HTML file

369
00:12:09.520 --> 00:12:11.160
that has some TypeScript in it.

370
00:12:11.160 --> 00:12:12.960
So you can see that we've got an interface

371
00:12:12.960 --> 00:12:16.320
here and we've got some RPC functions,

372
00:12:16.320 --> 00:12:17.920
which we'll look at in a second.

373
00:12:17.920 --> 00:12:19.820
And if I scroll down, we see

374
00:12:19.820 --> 00:12:21.860
the HTML for the page. The first thing

375
00:12:21.860 --> 00:12:24.380
I want you to notice is that this HTML,

376
00:12:24.700 --> 00:12:26.940
the syntax for it looks very much

377
00:12:26.940 --> 00:12:29.540
like regular HTML.

378
00:12:29.540 --> 00:12:31.540
This is not a different dialect.

379
00:12:31.540 --> 00:12:33.100
There's a little bit of extension

380
00:12:33.100 --> 00:12:34.820
to the language.

381
00:12:34.820 --> 00:12:36.640
So we can add these constructor attributes,

382
00:12:36.640 --> 00:12:39.460
which give this template these variables

383
00:12:39.460 --> 00:12:41.600
that can be provided by a caller.

384
00:12:41.600 --> 00:12:42.820
But other than that, this really just

385
00:12:42.820 --> 00:12:44.840
looks like HTML.

386
00:12:44.840 --> 00:12:47.620
So you can hand this off to another agent.

387
00:12:47.620 --> 00:12:49.660
You can hand it off to another human being.

388
00:12:49.660 --> 00:12:52.300
It's very beautifully written, and it's easy

389
00:12:52.300 --> 00:12:54.600
to read, and it's really just a standard

390
00:12:54.600 --> 00:12:56.640
language that everybody should know.

391
00:12:56.640 --> 00:12:58.560
The second thing to point out is we have

392
00:12:58.560 --> 00:13:00.840
this ability to refactor common user

393
00:13:00.840 --> 00:13:03.100
interface code into their own templates.

394
00:13:03.100 --> 00:13:04.980
So this is an example of the site layout,

395
00:13:05.320 --> 00:13:07.680
which has this isAdmin constructor

396
00:13:07.680 --> 00:13:09.400
attribute that we can provide it.

397
00:13:10.600 --> 00:13:13.000
And then inside of that is the content,

398
00:13:13.000 --> 00:13:14.320
the default content that will go

399
00:13:14.320 --> 00:13:15.760
inside of the site layout.

400
00:13:15.760 --> 00:13:18.440
So you can create these user

401
00:13:18.440 --> 00:13:19.820
interfaces that can be reused

402
00:13:19.820 --> 00:13:21.780
across all of your pages. So if I use

403
00:13:22.680 --> 00:13:25.400
Go to Definition in Visual Studio Code,

404
00:13:25.840 --> 00:13:26.980
which we can do because

405
00:13:26.980 --> 00:13:28.700
all of these templates are treated

406
00:13:28.700 --> 00:13:30.100
like symbols in Elements.

407
00:13:30.100 --> 00:13:31.880
They're just like classes or functions.

408
00:13:32.240 --> 00:13:34.020
And here's the reusable template over

409
00:13:34.020 --> 00:13:37.320
in the shared templates site layout folder.

410
00:13:37.320 --> 00:13:40.140
And it has this constructor attribute,

411
00:13:40.140 --> 00:13:42.960
public isAdmin, that's of type Boolean,

412
00:13:42.960 --> 00:13:45.060
and the default value is false.

413
00:13:45.060 --> 00:13:46.640
And so you can see the agent's quite good

414
00:13:46.640 --> 00:13:48.340
at writing this HTML,

415
00:13:48.340 --> 00:13:50.540
factoring it out so that this can be reused

416
00:13:50.540 --> 00:13:51.920
across your different pages.

417
00:13:51.920 --> 00:13:53.840
And this is going to make all the difference

418
00:13:53.840 --> 00:13:55.620
in the world when you're trying to build an

419
00:13:55.620 --> 00:13:57.800
application that's maintainable over time.

420
00:13:57.800 --> 00:13:59.480
The guardrails that are provided

421
00:13:59.480 --> 00:14:00.940
by the build tooling, and also

422
00:14:00.940 --> 00:14:02.940
by the framework and the HTML language,

423
00:14:02.940 --> 00:14:04.660
give the agent what it needs

424
00:14:04.660 --> 00:14:07.100
to make a lot of ferocious progress without

425
00:14:07.100 --> 00:14:09.020
worrying about breaking things and creating

426
00:14:09.020 --> 00:14:10.700
something that's a total spaghetti mess.

427
00:14:10.700 --> 00:14:12.400
So that's the Elements

428
00:14:12.400 --> 00:14:14.120
HTML templating system.

429
00:14:14.120 --> 00:14:16.160
If we go back here at the top, if you,

430
00:14:16.160 --> 00:14:18.140
you might have seen some of these functions

431
00:14:18.140 --> 00:14:19.620
here. We can write TypeScript

432
00:14:19.620 --> 00:14:21.080
right into the HTML file.

433
00:14:21.080 --> 00:14:23.200
They will be stripped out so that they

434
00:14:23.200 --> 00:14:24.540
don't go to the browser automatically.

435
00:14:24.540 --> 00:14:27.860
And notice this RPC function right here.

436
00:14:27.860 --> 00:14:29.960
This means that this function is going to be

437
00:14:29.960 --> 00:14:32.300
callable from the browser to the server.

438
00:14:32.700 --> 00:14:34.620
And it has some SQL in it that, again,

439
00:14:34.620 --> 00:14:36.720
the agent is very, very fast at writing SQL.

440
00:14:36.720 --> 00:14:38.720
And this particular function is called

441
00:14:38.720 --> 00:14:40.340
setSubscribed.

442
00:14:40.340 --> 00:14:42.000
So this is if, presumably, if somebody wants

443
00:14:42.000 --> 00:14:44.660
to subscribe or unsubscribe from the email.

444
00:14:44.660 --> 00:14:46.220
And what it does, it says, update the users

445
00:14:46.220 --> 00:14:47.680
table, set subscribed equal

446
00:14:47.680 --> 00:14:49.040
to the value that's provided,

447
00:14:49.040 --> 00:14:52.420
and where the ID is equal to the user

448
00:14:52.420 --> 00:14:53.840
ID of the person who's logged in.

449
00:14:53.840 --> 00:14:56.020
And if nobody's logged in, throw an error.

450
00:14:56.480 --> 00:14:59.020
And if the user's not logged in,

451
00:14:59.020 --> 00:15:00.620
throw an error here as well.

452
00:15:00.620 --> 00:15:02.280
So this is a secure function

453
00:15:02.280 --> 00:15:04.420
that is only callable over the server.

454
00:15:04.420 --> 00:15:05.920
Now let's say that the agent

455
00:15:05.920 --> 00:15:07.960
or the user makes a mistake and they

456
00:15:07.960 --> 00:15:10.240
forget to make this an RPC function.

457
00:15:10.240 --> 00:15:11.520
And now, oops, this is now

458
00:15:11.520 --> 00:15:13.640
a function that's gonna go to the browser.

459
00:15:13.640 --> 00:15:15.440
And if I save this, I immediately get

460
00:15:15.440 --> 00:15:17.440
a security error over on the left.

461
00:15:17.440 --> 00:15:19.700
So this security error, it says I've got

462
00:15:19.700 --> 00:15:21.860
one error in the template eHTML,

463
00:15:21.860 --> 00:15:24.280
and it says security error, you cannot

464
00:15:24.280 --> 00:15:26.880
call server code from the browser

465
00:15:26.880 --> 00:15:28.200
without going through an RPC function,

466
00:15:28.200 --> 00:15:30.560
and it tells you how to fix that problem.

467
00:15:31.000 --> 00:15:33.080
And if you scroll down a little bit,

468
00:15:33.080 --> 00:15:34.920
it's so zoomed in, it might be a little hard

469
00:15:34.920 --> 00:15:36.640
to see, but it shows you where the problem

470
00:15:36.640 --> 00:15:38.380
is and it gives you a call stack.

471
00:15:38.380 --> 00:15:40.420
And your agent is gonna see that as well,

472
00:15:40.420 --> 00:15:42.680
and the solution is very simple.

473
00:15:42.680 --> 00:15:45.120
You just add the RPC tag, build tag back,

474
00:15:45.120 --> 00:15:47.700
and now you're back to an okay state.

475
00:15:48.020 --> 00:15:50.220
So this is an example of the Elements

476
00:15:50.220 --> 00:15:52.060
tooling making it essentially impossible,

477
00:15:52.060 --> 00:15:53.680
or very difficult,

478
00:15:53.680 --> 00:15:55.840
to cause security problems.

479
00:15:56.380 --> 00:15:57.860
And any kind of SQL code that's

480
00:15:57.860 --> 00:16:00.140
called can only be called on the server.

481
00:16:00.140 --> 00:16:01.740
We will never ship that to the browser.

482
00:16:01.740 --> 00:16:03.000
You always have to go through an RPC

483
00:16:03.000 --> 00:16:04.840
function, and then you can authenticate

484
00:16:04.840 --> 00:16:06.600
that function using the very basic

485
00:16:06.600 --> 00:16:09.760
primitives like session or get

486
00:16:09.760 --> 00:16:13.120
or throw the session data

487
00:16:13.120 --> 00:16:15.040
that's on the session, like the user ID.

488
00:16:16.240 --> 00:16:17.820
Next up, I opened up the jobs folder,

489
00:16:17.820 --> 00:16:19.720
and jobs are just classes

490
00:16:19.720 --> 00:16:22.060
that allow you to put some work

491
00:16:22.060 --> 00:16:24.100
into a queue and have it be processed

492
00:16:24.100 --> 00:16:26.360
off the main application thread.

493
00:16:26.360 --> 00:16:28.360
And this is helpful for performance,

494
00:16:28.720 --> 00:16:31.360
for retrying jobs if they fail.

495
00:16:31.360 --> 00:16:32.700
Generally, any production application

496
00:16:32.700 --> 00:16:35.040
is going to have some kind of job system.

497
00:16:35.040 --> 00:16:36.580
And in Elements that is baked into

498
00:16:36.580 --> 00:16:38.040
the tooling. And so you can just write

499
00:16:38.040 --> 00:16:40.140
your jobs, or your agent can write the jobs.

500
00:16:40.500 --> 00:16:42.680
And the queue and the ability to work,

501
00:16:42.680 --> 00:16:43.780
to have workers pull off

502
00:16:43.780 --> 00:16:45.440
of that queue and service those jobs,

503
00:16:45.440 --> 00:16:47.300
is automatically part of your deployment.

504
00:16:47.300 --> 00:16:48.520
You don't need to pay for an extra

505
00:16:48.520 --> 00:16:49.820
SaaS subscription to get that.

506
00:16:49.820 --> 00:16:51.900
So here's the send newsletter job.

507
00:16:51.900 --> 00:16:53.720
This is the job that gets called in order

508
00:16:53.720 --> 00:16:55.260
to create a new newsletter

509
00:16:55.260 --> 00:16:57.220
and send that out to customers.

510
00:16:57.640 --> 00:16:59.360
Finally, let's open up the emails folder.

511
00:16:59.960 --> 00:17:01.960
Emails are also baked into Elements,

512
00:17:01.960 --> 00:17:05.140
and they're just regular eHTML files,

513
00:17:05.140 --> 00:17:06.960
but we use this @email build

514
00:17:06.960 --> 00:17:08.720
tag to mark it as an email.

515
00:17:09.120 --> 00:17:11.280
And what that does is it ensures

516
00:17:11.280 --> 00:17:14.560
that the style sheets are all

517
00:17:14.560 --> 00:17:17.400
inlined into the email that gets sent,

518
00:17:17.400 --> 00:17:19.220
because usually email clients

519
00:17:19.220 --> 00:17:21.140
like Gmail will not allow

520
00:17:21.140 --> 00:17:23.240
style sheets to be pulled in externally,

521
00:17:23.240 --> 00:17:24.600
so we have to do a little bit of extra

522
00:17:24.600 --> 00:17:27.180
linking in order to get an email to serve

523
00:17:27.180 --> 00:17:31.000
properly into most email clients.

524
00:17:31.000 --> 00:17:33.100
But other than that, it's just regular HTML.

525
00:17:33.100 --> 00:17:34.440
We've got constructor attributes,

526
00:17:34.440 --> 00:17:36.420
just like any other HTML template,

527
00:17:36.420 --> 00:17:38.740
and this is your email.

528
00:17:38.740 --> 00:17:40.560
We can also render these emails

529
00:17:40.560 --> 00:17:42.100
in the browser. That gives us a nice,

530
00:17:42.100 --> 00:17:43.360
easy way to see what they're going to look

531
00:17:43.360 --> 00:17:45.340
like before the user sees it.

532
00:17:45.340 --> 00:17:47.600
Now, the style sheet that's imported looks

533
00:17:47.600 --> 00:17:50.340
like regular CSS, just like any other page.

534
00:17:50.340 --> 00:17:51.920
And again, just like the other languages

535
00:17:51.920 --> 00:17:53.580
in Elements, we try to stick

536
00:17:53.580 --> 00:17:55.280
to the standards as much as possible

537
00:17:55.280 --> 00:17:56.880
without introducing abstractions.

538
00:17:56.880 --> 00:17:58.660
We don't have a CSS

539
00:17:58.660 --> 00:18:02.120
tool library that kind of takes you away

540
00:18:02.120 --> 00:18:04.380
from regular CSS. You just write CSS.

541
00:18:04.720 --> 00:18:06.500
We provide a framework of style

542
00:18:06.500 --> 00:18:08.360
rules and templates that you can use

543
00:18:08.360 --> 00:18:10.080
if you want, and if you don't want to,

544
00:18:10.080 --> 00:18:11.760
you can just have it get out of your way

545
00:18:11.760 --> 00:18:13.980
and write regular styles. So, the agent here

546
00:18:13.980 --> 00:18:16.200
has created a style sheet for these emails

547
00:18:17.060 --> 00:18:18.220
in regular CSS.

548
00:18:19.100 --> 00:18:20.980
And we can just import those into the HTML

549
00:18:20.980 --> 00:18:23.020
file and they'll be linked automatically.

550
00:18:23.620 --> 00:18:25.640
So this gives you a quick sense

551
00:18:25.640 --> 00:18:27.860
of the organization of the application

552
00:18:27.860 --> 00:18:29.540
and how the application framework from

553
00:18:29.540 --> 00:18:31.480
Elements is being used by the agent

554
00:18:31.480 --> 00:18:33.500
to create code that's really maintainable,

555
00:18:33.500 --> 00:18:34.880
that can be passed off to another

556
00:18:34.880 --> 00:18:36.520
agent over many, many, many sessions,

557
00:18:36.520 --> 00:18:38.040
or to another human.

558
00:18:38.040 --> 00:18:40.380
Let me show you one last thing,

559
00:18:40.380 --> 00:18:43.320
which is that the test files that the agent

560
00:18:43.320 --> 00:18:45.980
writes really help to maintain

561
00:18:45.980 --> 00:18:47.760
code that doesn't break over time.

562
00:18:47.760 --> 00:18:50.140
Here's an example of a test file that's

563
00:18:50.140 --> 00:18:52.260
associated with the accounts page. It looks

564
00:18:52.260 --> 00:18:54.520
like this has a couple of tests in it.

565
00:18:54.900 --> 00:18:57.600
Tests are really great for agents

566
00:18:57.600 --> 00:19:00.280
because they help the agent

567
00:19:00.280 --> 00:19:01.960
make sure that if it writes a new feature,

568
00:19:01.960 --> 00:19:04.520
it didn't break something that was already

569
00:19:04.520 --> 00:19:06.340
developed in the past. So, I'm going to open

570
00:19:06.340 --> 00:19:08.580
up a new terminal over here on the left,

571
00:19:08.580 --> 00:19:10.740
and I'm going to use a new command that

572
00:19:10.740 --> 00:19:12.800
we haven't seen yet called elements test.

573
00:19:12.800 --> 00:19:14.000
That's going to show me

574
00:19:14.000 --> 00:19:15.840
the results of all the tests.

575
00:19:15.840 --> 00:19:17.700
One of the things that you should notice is

576
00:19:17.700 --> 00:19:19.720
that there's a lot of tests, first of all.

577
00:19:19.720 --> 00:19:21.160
The second thing you should notice is just

578
00:19:21.160 --> 00:19:23.640
how fast I got those test results.

579
00:19:23.640 --> 00:19:24.820
I'm looking at this quickly, but

580
00:19:24.820 --> 00:19:26.300
I think that's 14 microseconds.

581
00:19:26.300 --> 00:19:28.900
We got all of the results of the test, and

582
00:19:28.900 --> 00:19:30.420
we can see that they're all passing here.

583
00:19:30.420 --> 00:19:32.840
So having very fast tests,

584
00:19:32.840 --> 00:19:34.620
where the state of the test is available

585
00:19:34.620 --> 00:19:36.420
in real time, that the agent can ask,

586
00:19:36.420 --> 00:19:37.860
hey, did I break anything, and it gets

587
00:19:37.860 --> 00:19:39.520
an answer immediately, not in 10 minutes

588
00:19:39.520 --> 00:19:41.340
or 15 minutes, is critically important.

589
00:19:41.340 --> 00:19:42.940
And the other thing to note is that when

590
00:19:42.940 --> 00:19:44.560
you deploy this application to production,

591
00:19:44.560 --> 00:19:47.400
these tests will be run as part

592
00:19:47.400 --> 00:19:49.240
of your deployment, and if any of them

593
00:19:49.240 --> 00:19:50.780
are failing, it stops the deployment.

594
00:19:50.780 --> 00:19:52.260
So deployments in Elements are very,

595
00:19:52.260 --> 00:19:54.220
very safe. Okay, this was a deep

596
00:19:54.220 --> 00:19:55.360
dive into some of the code,

597
00:19:55.360 --> 00:19:56.680
but I thought it was important to show

598
00:19:56.680 --> 00:19:58.800
you around what the agent actually produced,

599
00:19:58.800 --> 00:20:00.800
so that you can feel confident that when

600
00:20:00.800 --> 00:20:02.580
you build your newsletter blog application,

601
00:20:02.580 --> 00:20:04.400
it's going to work the first time

602
00:20:04.400 --> 00:20:06.160
and also continue to work over time.

603
00:20:06.160 --> 00:20:07.640
If you have any questions, drop them into

604
00:20:07.640 --> 00:20:09.500
the comments, and have fun building.
