VK_SUBPASS_EXTERNAL references commands recorded\submitted before vkCmdBeginRenderPass or after vkCmdEndRenderpass.
In a case of a 101 example, the adjacent use is just swapchain, which requires an semaphore on acquire and semaphore on present. There is actually concrete note about this use case in the specification, at the end of 7.4.2. Semaphore Waiting.
Now, semaphore signal (before you present) already covers all previous memory access on the device, so you are all set without any further synchronization. But for educational purposes and code readability, it cannot hurt to add that dependency explicitly anyway:
VkSubpassDependency presentDependency{
0, // srcSubpass
VK_SUBPASS_EXTERNAL, // dstSubpass
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, // srcStageMask
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, // dstStageMask
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // srcAccessMask
0, // dstAccessMask
0, // dependencyFlags
};
Note dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, which practically means "synchronize with nothing". The srcStageMask covers your store op, but it would have been covered implicitly even if you do not list any Dependency.
Now the semaphore wait (for your swapchain image acquire semaphore) is sneaky. There's a sneaky vkQueueSubmit parameter, the pWaitDstStageMask. That parameter says the semaphore will not be waited sooner than the pipeline stage in pWaitDstStageMask. So you must actually put a dependency there that pushes the layout transition from your render pass after the semaphore wait:
pWaitDstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
VkSubpassDependency acquireDependency{
VK_SUBPASS_EXTERNAL, // srcSubpass
0, // dstSubpass
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, // srcStageMask
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, // dstStageMask
0, // srcAccessMask
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // dstAccessMask
VK_DEPENDENCY_BY_REGION_BIT, // dependencyFlags
};
Note that pWaitDstStageMask = srcStageMask, so an execution dependency chain is formed with the semaphore wait. This dependency also forces the layout transition away from initialLayout to happen inbetween the semaphore wait and the renderpass load op.
Refer to this diagram about the synchronization, and what and why it is needed:

For a more complex app it actually gets simpler. Refer to official synch. examples. You simply add a dependency there that is appropriate for the previous\next usage of the image.
E.g. if you perform compute (vkCmdDispatch) after the render pass, then you simply add a VK_SUBPASS_EXTERNAL dependency with dstStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT.